commit 23b61d3ea5595a66d928f84d079187853f685b6c Author: Nicholas Kirchner Date: Thu Aug 22 19:57:00 2013 -0500 Forked from revision 11 at http://sourceforge.net/p/x49gp/code/11/tree/ diff --git a/4950_92.bin b/4950_92.bin new file mode 100644 index 0000000..0c159b3 Binary files /dev/null and b/4950_92.bin differ diff --git a/49Gp_88.bin b/49Gp_88.bin new file mode 100644 index 0000000..469a9b5 Binary files /dev/null and b/49Gp_88.bin differ diff --git a/EqnData.lib b/EqnData.lib new file mode 100644 index 0000000..239d658 Binary files /dev/null and b/EqnData.lib differ diff --git a/EqnLib.lib b/EqnLib.lib new file mode 100644 index 0000000..42c4ce8 Binary files /dev/null and b/EqnLib.lib differ diff --git a/HP49GP_IO_PORT b/HP49GP_IO_PORT new file mode 100644 index 0000000..0b8c173 --- /dev/null +++ b/HP49GP_IO_PORT @@ -0,0 +1,185 @@ + +I/O Port A (23 I/O Bits): + + 22 (???) (output) + 21 (???) (output) + 20 (???) (output) + 19 (???) (output) + 18 (???) (output) + 17 (???) (output) + 16 (???) (output) + + 15 (???) (output) + 14 (???) (output) + 13 (???) (output) + 12 (???) (nGCS1) + 11 (???) (output) + 10 (???) (output) + 9 (???) (output) + 8 (???) (output) + + 7 (???) (output) + 6 (???) (output) + 5 (???) (ADDR20) + 4 (???) (ADDR19) + 3 (???) (ADDR18) + 2 (???) (ADDR17) + 1 (???) (ADDR16) + 0 (???) (ADDR0) + +I/O Port B (11 I/O Bits): + + 10 ??? (output) + 9 ??? (output) + 8 ??? (output) + 7 ??? (output) + 6 ??? (output) + 5 ??? (output) + 4 ??? (output) + 3 ??? (output) + 2 ??? (output) TIMER2 OUT (Piezo Speaker) + 1 ??? (output) + 0 ??? (output) + +I/O Port C (16 I/O Bits): + + 15 ??? (input) + 14 ??? (input) + 13 ??? (input) + 12 ??? (input) + 11 ??? (VD[3]) VD3 + 10 ??? (VD[2]) VD2 + 9 ??? (VD[1]) VD1 + 8 ??? (VD[0]) VD0 + + 7 ??? (output) + 6 ??? (output) + 5 ??? (output) + 4 ??? (VM) VM + 3 ??? (VFRAME) VFRAME + 2 ??? (VLINE) VLINE + 1 ??? (VCLK) VCLK + 0 ??? (output) + +I/O Port D (16 I/O Bits): + + 15 ??? (output) + 14 ??? (output) + 13 ??? (output) LCD SPI data + 12 ??? (output) LCD SPI clk + 11 ??? (output) + 10 ??? (output) + 9 ??? (output) LCD SPI chip select + 8 ??? (output) LCD SPI reset? + + 7 ??? (output) LCD enable? + 6 ??? (output) + 5 ??? (output) + 4 ??? (output) + 3 ??? (input) + 2 ??? (output) IrDA shutdown + 1 ??? (output) + 0 ??? (output) + +I/O Port E (16 I/O Bits): SD Card Stuff. + + 15 ??? (IICSDA) + 14 ??? (IICSCL) + 13 ??? (output) + 12 ??? (output) SPIMOSI0 (IrDA Tx) + 11 ??? (output) + 10 ??? (output) SDDAT3 + 9 ??? (output) SDDAT2 + 8 ??? (output) SDDAT1 + + 7 ??? (output) SDDAT0 + 6 ??? (output) SDCMD + 5 ??? (output) SDCLK + 4 ??? (output) + 3 ??? (output) + 2 ??? (output) + 1 ??? (output) + 0 ??? (output) + +IO Port F (8 I/O Bits): + + 7 ??? (output) + 6 KEYB (EINT6) Right Shift + 5 KEYB (EINT5) Left Shift + 4 KEYB (EINT4) Alpha + 3 SD (EINT3) SD Card Inserted + 2 ??? (output) + 1 ??? (output) + 0 KEYB (EINT0) ON + +I/O Port G (16 I/O Bits): + + 15 Column 7 (output) (Keys STO (K), NXT (L)) + 14 Column 6 (output) (Keys Up, Left, Down, Right, MODE (H), TOOL (I), VAR (J)) + 13 Column 5 (output) (Keys F1 (A) .. F6 (F), APPS (G)) + 12 Column 4 (output) (Keys HIST (M) .. EEX (V)) + 11 Column 3 (output) (Keys EVAL (N) .. 0) + 10 Column 2 (output) (Keys ' (O) .. .) + 9 Column 1 (output) (Keys SYMB (P) .. SPC) + 8 Column 0 (output) (Keys Backspace .. Enter) + + 7 Row 7 (input) + 6 Row 6 (input) + 5 Row 5 (input) + 4 Row 4 (input) + 3 Row 3 (input) + 2 Row 2 (input) + 1 Row 1 (input) + 0 ??? + +IO Port H (11 I/O Bits): + + 10 ??? (output) + 9 ??? (CLKOUT0) CLKOUT0 (UPLL: 48MHz) + 8 ??? (UEXTCLK) UEXTCLK (connected to CLKOUT0) + 7 ??? (output) RXD2 (IrDA) + 6 ??? (output) TXD2 (IrDA) + 5 ??? (output) + 4 ??? (output) + 3 ??? (output) RXD0 (HP50g) + 2 ??? (output) TXD0 (HP50g) + 1 ??? (output) /RTS0 (not used) + 0 ??? (output) /CTS0 (not used) + + +HP50g uses the 3rd letter in the SerialNo at offset 0x03ff0 to determine +whether to use the serial port 0 or not. + + +EXTINT: + + 0 rising edge + 1 falling edge + 2 falling edge + 3 rising edge + 4 rising edge enabled + 5 rising edge enabled + 6 rising edge enabled + 7 falling edge + + 8 falling edge + 9 falling edge enabled + 10 falling edge enabled + 11 falling edge enabled + 12 falling edge enabled + 13 falling edge enabled + 14 falling edge enabled + 15 falling edge enabled + + 16 falling edge + 17 falling edge + 18 falling edge + 19 falling edge + 20 falling edge + 21 falling edge + 22 falling edge + 23 falling edge + + +nRSTOUT n.c. +PWREN n.c. diff --git a/MEMORY b/MEMORY new file mode 100644 index 0000000..05d8b25 --- /dev/null +++ b/MEMORY @@ -0,0 +1,21 @@ +Saturn CPU Structure at + + 08003340 + +contains + + u32 Read[257]; Saturn -> ARM mapping table + u32 Write[257]; + + armptr = Read[saturnptr >> 12] | ((saturnptr & 0xfff) >> 1); + +"standard" Saturn mapping: + + 00000 -> 00060000 + ... ROM + 7ffff -> 0009ffff + + 80000 -> 08040000 + ... RAM + fffff -> 0807ffff + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5d5988a --- /dev/null +++ b/Makefile @@ -0,0 +1,321 @@ +# $Id: Makefile,v 1.29 2008/12/11 12:18:17 ecd Exp $ +# + +X49GP_DEBUG = \ + -DDEBUG_X49GP_MODULES \ + -DDEBUG_S3C2410_SRAM \ + -DDEBUG_S3C2410_MEMC \ + -DDEBUG_S3C2410_INTC \ + -DDEBUG_S3C2410_POWER \ + -DDEBUG_S3C2410_LCD \ + -DDEBUG_S3C2410_UART \ + -DDEBUG_S3C2410_TIMER \ + -DDEBUG_S3C2410_USBDEV \ + -DDEBUG_S3C2410_WATCHDOG \ + -DDEBUG_S3C2410_IO_PORT \ + -DDEBUG_S3C2410_RTC \ + -DDEBUG_S3C2410_ADC \ + -DDEBUG_S3C2410_SDI \ + -DDEBUG_S3C2410_SPI \ + -DDEBUG_X49GP_SYSCALL \ + -DDEBUG_X49GP_FLASH_READ \ + -DDEBUG_X49GP_FLASH_WRITE \ + -UDEBUG_X49GP_SYSRAM_READ \ + -UDEBUG_X49GP_SYSRAM_WRITE \ + -UDEBUG_X49GP_ERAM_READ \ + -UDEBUG_X49GP_ERAM_WRITE \ + -UDEBUG_X49GP_IRAM_READ \ + -UDEBUG_X49GP_IRAM_WRITE \ + -DDEBUG_X49GP_TIMER_IDLE \ + -DDEBUG_X49GP_ARM_IDLE \ + -DDEBUG_X49GP_ENABLE_IRQ \ + -DDEBUG_X49GP_UI + +DEBUG = -g # -pg + +#2.09 +FIRMWARE = 4950_92.bin +#2.10-7 +#FIRMWARE = hp49g-u.bin +#HPGCC3 (copy HPGCC3 ROM first) +#FIRMWARE = 49_hpgcc.bin +#2.15 +#FIRMWARE = 4950_215.bin + +BOOT49GP = boot-49g+.bin +BOOT50G = boot-50g.bin +SERIAL49GP = DE00000001 +SERIAL50G = DEA0000001 +COPYRIGHT = Kinposhcopyright + +QEMU_DEFINES = -DTARGET_ARM -DX49GP \ + -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ + -fno-strict-aliasing + +# Use this to debug +# DEFINES = $(X49GP_DEBUG) $(QEMU_DEFINES) +# Use this for speed +DEFINES = $(QEMU_DEFINES) + +ifdef QEMU_OLD +QEMUSRC = qemu/prepare.sh \ + $(wildcard qemu/patches/*.patch) \ + $(wildcard qemu/patches/*.diff) + +QEMU=qemu/qemu +else +QEMUSRC = +QEMU=qemu/qemu-git +endif + +QEMUMAKE = $(shell if [ "`uname -s`" = "Linux" -a "`uname -m`" = "sun4u" ]; then echo "sparc32 $(MAKE)"; else echo "$(MAKE)"; fi) + +ifdef QEMU_OLD +QEMU_DIR=$(QEMU) +QEMU_DEFINES+=-DQEMU_OLD +X49GP_LDFLAGS = -L$(QEMU)/arm-softmmu +X49GP_LIBS = -lqemu -lz +else +QEMU_DIR=qemu/qemu-git +QEMU_DIR_BUILD=$(QEMU_DIR)/arm-softmmu +QEMU_DEFINES+=-DNEED_CPU_H +X49GP_LDFLAGS= +X49GP_LIBS= $(QEMU_DIR_BUILD)/exec.o $(QEMU_DIR_BUILD)/translate-all.o $(QEMU_DIR_BUILD)/cpu-exec.o $(QEMU_DIR_BUILD)/translate.o $(QEMU_DIR_BUILD)/fpu/softfloat.o $(QEMU_DIR_BUILD)/op_helper.o $(QEMU_DIR_BUILD)/helper.o $(QEMU_DIR_BUILD)/disas.o $(QEMU_DIR_BUILD)/i386-dis.o $(QEMU_DIR_BUILD)/arm-dis.o $(QEMU_DIR_BUILD)/tcg/tcg.o $(QEMU_DIR_BUILD)/iwmmxt_helper.o $(QEMU_DIR_BUILD)/neon_helper.o +endif +QEMU_INCDIR=$(QEMU_DIR) +QEMU_INC=-I$(QEMU_INCDIR)/target-arm -I$(QEMU_INCDIR) -I$(QEMU_INCDIR)/fpu -I$(QEMU_INCDIR)/arm-softmmu + +X49GP_INCLUDES = -Iinclude -Ibitmaps $(QEMU_INC) + +INCLUDES = $(GDB_INCLUDES) $(X49GP_INCLUDES) + +ifdef QEMU_OLD +CC = $(shell if [ "`uname -s`" = "Darwin" ]; then echo "gcc"; else echo "gcc-3.4"; fi) +else +CC = gcc +endif +LD = $(CC) +AR = ar +RANLIB = ranlib + +CC += $(shell if [ "`uname -m`" = "sparc64" -o "`uname -m`" = "sun4u" ]; then echo "-mcpu=ultrasparc -m32"; fi) + +COCOA_LIBS=$(shell if [ "`uname -s`" = "Darwin" ]; then echo "-F/System/Library/Frameworks -framework Cocoa -framework IOKit"; fi) + +CFLAGS = -O2 -Wall $(DEBUG) $(INCLUDES) $(DEFINES) +LDFLAGS = $(DEBUG) $(X49GP_LDFLAGS) $(GDB_LDFLAGS) +LDLIBS = $(X49GP_LIBS) $(GDB_LIBS) $(COCOA_LIBS) + +MAKEDEPEND = $(CC) -MM + +CFLAGS += $(shell pkg-config --cflags gtk+-2.0) +LDFLAGS += $(shell pkg-config --libs gtk+-2.0) + +ifdef QEMU_OLD +export MAKE MAKEDEPEND CC LD AR RANLIB CFLAGS LDFLAGS +endif + +LIBS = $(QEMU) + +SRCS = main.c module.c flash.c sram.c s3c2410.c \ + s3c2410_sram.c \ + s3c2410_memc.c \ + s3c2410_intc.c \ + s3c2410_power.c \ + s3c2410_lcd.c \ + s3c2410_nand.c \ + s3c2410_uart.c \ + s3c2410_timer.c \ + s3c2410_usbdev.c \ + s3c2410_watchdog.c \ + s3c2410_io_port.c \ + s3c2410_rtc.c \ + s3c2410_adc.c \ + s3c2410_spi.c \ + s3c2410_sdi.c \ + s3c2410_arm.c \ + ui.c timer.c tiny_font.c symbol.c \ + gdbstub.c block.c + +OBJS = $(SRCS:.c=.o) + +ifdef QEMU_OLD +VVFATOBJS = $(QEMU)/arm-softmmu/block-vvfat.o \ + $(QEMU)/arm-softmmu/block-qcow.o \ + $(QEMU)/arm-softmmu/block-raw.o +else +# TEMPO hack +VVFATOBJS = block-vvfat.o \ + block-qcow.o \ + block-raw.o +endif + +ifdef QEMU_OLD +VVFATOBJS += $(QEMU)/arm-softmmu/cutils.o +else +VVFATOBJS += $(QEMU_DIR)/cutils.o +endif + +TARGET = x49gp + +all: do-it-all + +ifeq (.depend,$(wildcard .depend)) +include .depend +do-it-all: $(QEMU) $(TARGET) flash-49g+ flash-50g sram s3c2410-sram +else +do-it-all: depend-and-build +endif + +ifdef QEMU_OLD +$(TARGET): $(OBJS) $(VVFATOBJS) $(QEMU)/arm-softmmu/libqemu.a + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(VVFATOBJS) $(LDLIBS) +else +$(TARGET): $(OBJS) $(VVFATOBJS) $(X49GP_LIBS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(VVFATOBJS) $(LDLIBS) +endif + +flash-49g+: $(BOOT49GP) flash-noboot + @cp flash-noboot $@ + @/bin/echo -n "$@: Copy boot loader \"$(BOOT49GP)\" to "; echo "0" + @dd if=$(BOOT49GP) of=$@ bs=16 seek=0 conv=notrunc 2>/dev/null + @/bin/echo -n "$@: Set serial number \"$(SERIAL49GP)\" at "; expr 16 \* 1023 + @/bin/echo -n "$(SERIAL49GP)" >serialno + @dd if=serialno of=$@ bs=16 seek=1023 conv=notrunc 2>/dev/null + @rm -f serialno + +flash-50g: $(BOOT50G) flash-noboot + @cp flash-noboot $@ + @/bin/echo -n "$@: Copy boot loader \"$(BOOT50G)\" to "; echo "0" + @dd if=$(BOOT50G) of=$@ bs=16 seek=0 conv=notrunc 2>/dev/null + @/bin/echo -n "$@: Set serial number \"$(SERIAL50G)\" at "; expr 16 \* 1023 + @/bin/echo -n "$(SERIAL50G)" >serialno + @dd if=serialno of=$@ bs=16 seek=1023 conv=notrunc 2>/dev/null + @rm -f serialno + +flash-noboot: $(FIRMWARE) + @/bin/echo -n "$@: Fill ff: 0 " + @/bin/echo -ne "\377" >one + @COUNT=0; \ + SIZE=1; \ + while [ $${COUNT} -le 20 ]; do \ + cat one one >one2; \ + mv one2 one; \ + COUNT=`expr $${COUNT} + 1`; \ + SIZE=`expr $${SIZE} + $${SIZE}`; \ + /bin/echo -n "."; \ + done; \ + echo " $${SIZE}" + @mv one $@ + @/bin/echo -n "$@: Mark blocks:" + @OFFSET=524544; \ + for block in 02 03 04 05 06 07 10 11 12 13 14 15; do \ + /bin/echo -ne "\360\0$${block}\000\000\000" >header; \ + dd if=header of=$@ bs=1 seek=$${OFFSET} conv=notrunc 2>/dev/null; \ + /bin/echo -n " $${OFFSET}"; \ + OFFSET=`expr $${OFFSET} + 131072`; \ + done; \ + echo "" + @/bin/echo -n "$@: Copy firmware \"$(FIRMWARE)\" to "; expr 16 \* 1024 + @dd if=hp49g-u.bin of=$@ bs=16 seek=1024 conv=notrunc 2>/dev/null + @dd if=$(FIRMWARE) of=$@ bs=16 seek=1024 conv=notrunc 2>/dev/null + @/bin/echo -n "$@: Set copyright \"$(COPYRIGHT)\" at "; expr 16 \* 1024 + @/bin/echo -n "$(COPYRIGHT)" >copyright + @dd if=copyright of=$@ bs=16 seek=1024 conv=notrunc 2>/dev/null + @rm -f one one2 header copyright + +sram: + dd if=/dev/zero of=$@ bs=1024 count=512 + +s3c2410-sram: + dd if=/dev/zero of=$@ bs=1024 count=4 + +sdcard: +ifeq ($(shell uname),Darwin) + rm -f sdcard.dmg + hdiutil create sdcard -megabytes 64 -fs MS-DOS -volname x49gp +else + /sbin/mkdosfs -v -C -S 512 -f 2 -F 16 -r 512 -R 2 -n "x49gp" $@ 65536 +endif + +config: + ./newconfig + +sim: dummy + $(MAKE) -C $@ + +ifdef QEMU_OLD +$(QEMU): $(QEMU)/config-host.h dummy + $(QEMUMAKE) -C $@ + +$(QEMU)/config-host.h: $(QEMUSRC) + cd qemu; ./prepare.sh + make -C . all + +$(QEMU)/arm-softmmu/%.o: $(QEMU)/%.c + $(QEMUMAKE) BASE_CFLAGS=-DX49GP -C $(QEMU)/arm-softmmu $(shell basename $@) +else +$(QEMU)/config-host.h: $(QEMUSRC) + ( cd $(QEMU); \ + ./configure-small --extra-cflags=-DX49GP; \ + $(QEMUMAKE) -f Makefile-small ) + +$(QEMU)/arm-softmmu/%.o: $(QEMU)/%.c + $(QEMUMAKE) -C $(QEMU) -f Makefile-small +endif + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +ifdef QEMU_OLD +clean-libs: + if [ -n "$(LIBS)" ]; then \ + for d in $(LIBS); do \ + $(MAKE) -C $$d clean; \ + done \ + fi + +clean: clean-libs + rm -f *.o core *~ .depend + +distclean: clean + rm -rf $(QEMU) + rm -f $(TARGET) flash-49g+ flash-50g flash-noboot sram s3c2410-sram + rm -f config + +depend-and-build: depend + $(MAKE) -C . all + +depend-libs: $(QEMU)/config-host.h + if [ -n "$(LIBS)" ]; then \ + for d in $(LIBS); do \ + if [ "$$d" != "$(QEMU)" ]; then \ + $(MAKE) -C $$d depend; \ + fi \ + done \ + fi + +depend: depend-libs + $(MAKEDEPEND) $(CFLAGS) $(SRCS) >.depend +else +clean-qemu: + $(MAKE) -C $(QEMU) -f Makefile-small clean + +clean: clean-qemu + rm -f *.o core *~ .depend + +distclean: clean + $(MAKE) -C $(QEMU) -f Makefile-small distclean + rm -f $(TARGET) flash-49g+ flash-50g flash-noboot sram s3c2410-sram + rm -f config + +depend-libs: $(QEMU)/config-host.h + +depend-and-build: depend + $(MAKE) -C . all + +depend: depend-libs + $(MAKEDEPEND) $(CFLAGS) $(SRCS) >.depend +endif + +dummy: diff --git a/README b/README new file mode 100644 index 0000000..1b0456e --- /dev/null +++ b/README @@ -0,0 +1,63 @@ +Next steps: + + - Verify Locks needed + - Audit Keyboard <-> IO Port Interaction + - Add remote gdb interface + + +Registers to check access to: + + IO PORT MISCCR + MMU FSR + MMU FAR + MMU Alignment Checks in general + MMU r7: Wait for Interrupt + + +File Manager: + + Read from 0x08080000: Probe memory size??? + -> Add mirrored mapping of SRAM? + + +Annunciators: + + Bits set in Column 132 of the LCD screen memory: + + Row 0: Transmit + Row 1: Left Shift + Row 2: Right Shift + Row 3: Alpha + Row 4: Battery + Row 5: Busy + +IRQ Branch Table: + + 08000020: IRQ reads 08000020 + (IRQOFFSET << 2), branches there + + IRQ returns with "subs pc, lr, #4" + + + +The speed of the emulator is an issue... + +It is running about 20 times SLOWER than the original calculator at the moment +on my 400 MHz UltraSparc. There will be quite some speedup running on a modern +PC or workstation with faster processor. Also, at the moment I have a lot of debugging +enabled, which slows down the emulator. + +Getting the full 75 MHz out of the emulated ARM core will be hard work, I have not +looked into the potential optimizations that can be done in the core emulator, but +there are some things done during every instruction that we don't need for this +machine. + +There are generally two options to speed up or use the emulator: + +1. Emulate the hardware as closely as possible to help debug programms digging + into the s3c2410. +2. Emulate the saturn part to make it a usable calculator. Here one could implement + some of the most often used KOS syscalls directly in the emulator without doing + these on the emulated ARM core. This would speed up the calculator significantly. + +Optimally there will be a runtime option to switch between these two modes. + diff --git a/README.QEMU b/README.QEMU new file mode 100644 index 0000000..40777dc --- /dev/null +++ b/README.QEMU @@ -0,0 +1 @@ +Fix ldX_le/stX_le on sparc: use ASI_LE diff --git a/README.QUICKSTART b/README.QUICKSTART new file mode 100644 index 0000000..b61586f --- /dev/null +++ b/README.QUICKSTART @@ -0,0 +1,158 @@ +Quick Start Guide +04/25/2010 +Egan Ford + +NOTE: READ ALL INSTRUCTIONS + +Prereqs: + +* OS/X 10.6 64-bit: + + * Install X11, Xcode (from your installation media) in that order. + * Install Macports (macports.org), then: + + sudo port install gtk2 + sudo port install pkgconfig + + +* Ubuntu 9.04 32-bit, 9.04 64-bit, 9.10 32-bit, 9.10 64-bit: + + sudo apt-get install libgtk2.0-dev + sudo apt-get install subversion + + +* RedHat/CentOS 5.4 64-bit, Fedora 12 64-bit: + + sudo yum install subversion gtk2-devel + +------------------------------------------------------------------------ + +Start up X11 and use xterm + +------------------------------------------------------------------------ + +Download x49gp source: + +svn co http://x49gp.svn.sourceforge.net/svnroot/x49gp x49gp + +------------------------------------------------------------------------ + +Edit FIRMWARE (optional): + +The default firmware will be 4950_92.bin, for HPGCC3 development copy +49_hpgcc.bin in to x49gp and change FIRMWARE in the Makefile. + +------------------------------------------------------------------------ + +Build: + +cd x49gp +make +make sdcard +make config + +------------------------------------------------------------------------ + +Mount SD card: + +OS/X: + +open sdcard.dmg + +Linux: + +sudo mkdir -p /Volumes/X49GP/ +sudo mount -o loop sdcard /Volumes/X49GP + +------------------------------------------------------------------------ + +Put stuff in SD, e.g.: + +OS/X: + +cp BACKUP /Volumes/X49GP/ + +Linux: + +sudo cp BACKUP /Volumes/X49GP/ + +NOTE: If using HPGCC2 don't forget the the ARMToolbox. + +------------------------------------------------------------------------ + +Eject SD: + +OS/X: + +hdiutil detach $(df | grep -i x49gp | head -1 | awk '{print $1}') + +Linux: + +sudo umount /Volumes/X49GP + +------------------------------------------------------------------------ + +Run: + +./x49gp config + +------------------------------------------------------------------------ + +Where's the key labels? + +Good question. This is a bug when compiled for 64-bit platforms. + +Hack: + +cp hp50g-hack.png hp50g.png + +------------------------------------------------------------------------ + +Do stuff, e.g.: + +Restore backup: + +BACKUP +3 +->TAG +RESTORE + +Install ARMToolbox (HPGCC2): + +2 +SETUP.BIN +3 +->TAG +RCL +EVAL +(Right Click ON, Left Click C) + +------------------------------------------------------------------------ + +To Exit Emulator + +* ctrl-c to exit (from launch window) + +------------------------------------------------------------------------ + +Start Over: + +* clean slate? + +rm -f flash-49g+ flash-50g flash-noboot sram s3c2410-sram +make flash-49g+ flash-50g flash-noboot sram s3c2410-sram +./newconfig + +* soft reset only? + +./newconfig + +------------------------------------------------------------------------ + +Known Limitations: + +* HPGCC SD Card I/O + . libfsystem unavailable. + . f* calls unstable (HPGCC2) + . f* calls stable (HPGCC3) + diff --git a/README.config b/README.config new file mode 100644 index 0000000..1719a90 --- /dev/null +++ b/README.config @@ -0,0 +1,11 @@ +[x49gp] +basename=.x49gp +[x49gp] +name=hp49g+ +image=hp49g+.png +[flash] +filename=flash +[sram] +filename=sram +[s3c2410-sram] +filename=s3c2410-sram diff --git a/SYSCALL-28-TRACE b/SYSCALL-28-TRACE new file mode 100644 index 0000000..64c7a6c --- /dev/null +++ b/SYSCALL-28-TRACE @@ -0,0 +1,327 @@ +sp 0801e314, lr 0001ebb4, pc 00036ae0, insn e8bd80ff: ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r7, pc} +sp 0801e338, lr 0001ebb4, pc 0001ebb4, insn e20000ff: and r0, r0, #255 ; 0xff +sp 0801e338, lr 0001ebb4, pc 0001ebb8, insn e8bd8008: ldmia sp!, {r3, pc} +sp 0801e340, lr 0001ebb4, pc 0001ebec, insn e3500000: cmp r0, #0 ; 0x0 +sp 0801e340, lr 0001ebb4, pc 0001ebf0, insn 0afffffc: beq 0x0001ebe8 +sp 0801e340, lr 0001ebb4, pc 0001ebe8, insn ebffffee: bl 0x0001eba8 +sp 0801e340, lr 0001ebec, pc 0001eba8, insn e92d4008: stmdb sp!, {r3, lr} +sp 0801e338, lr 0001ebec, pc 0001ebac, insn e3a0001c: mov r0, #28 ; 0x1c +sp 0801e338, lr 0001ebec, pc 0001ebb0, insn ebfffef9: bl 0x0001e79c +sp 0801e338, lr 0001ebb4, pc 0001e79c, insn ea00627b: b 0x00037190 +sp 0801e338, lr 0001ebb4, pc 00037190, insn ef000000: swi 0x00000000 +ARMul_OSHandleSWI: PC 00037198: syscall 28: args 08000a98 0000004a 00037ed4 00000000 0000162e 08003b40 00001629 +sp 080004fc, lr 00037194, pc 00000008, insn ea000035: b 0x000000e4 +sp 080004fc, lr 00037194, pc 000000e4, insn e24dd004: sub sp, sp, #4 ; 0x4 +sp 080004f8, lr 00037194, pc 000000e8, insn e92d0300: stmdb sp!, {r8, r9} +sp 080004f0, lr 00037194, pc 000000ec, insn e3a08680: mov r8, #134217728 ; 0x8000000 +sp 080004f0, lr 00037194, pc 000000f0, insn e5989008: ldr r9, [r8, #8] +sp 080004f0, lr 00037194, pc 000000f4, insn e58d9008: str r9, [sp, #8] +sp 080004f0, lr 00037194, pc 000000f8, insn e8bd8300: ldmia sp!, {r8, r9, pc} +sp 080004fc, lr 00037194, pc 000369b8, insn e94d3000: stmdb sp, {ip, sp}^ +sp 080004fc, lr 00037194, pc 000369bc, insn e59fe144: ldr lr, [pc, #324] ; 0x00036b08 +sp 080004fc, lr 08002360, pc 000369c0, insn e5dec000: ldrb ip, [lr] +sp 080004fc, lr 08002360, pc 000369c4, insn e28cc001: add ip, ip, #1 ; 0x1 +sp 080004fc, lr 08002360, pc 000369c8, insn e5cec000: strb ip, [lr] +sp 080004fc, lr 08002360, pc 000369cc, insn e91d3000: ldmdb sp, {ip, sp} +sp 0801e338, lr 08002360, pc 000369d0, insn e10fe000: mrs lr, CPSR +sp 0801e338, lr 60000093, pc 000369d4, insn e3cee0c0: bic lr, lr, #192 ; 0xc0 +sp 0801e338, lr 60000013, pc 000369d8, insn e121f00e: msr CPSR_c, lr +sp 0801e338, lr 60000013, pc 000369dc, insn e3300000: teq r0, #0 ; 0x0 +sp 0801e338, lr 60000013, pc 000369e0, insn 0a00001c: beq 0x00036a58 +sp 0801e338, lr 60000013, pc 000369e4, insn e3500064: cmp r0, #100 ; 0x64 +sp 0801e338, lr 60000013, pc 000369e8, insn aa000001: bge 0x000369f4 +sp 0801e338, lr 60000013, pc 000369ec, insn ebffa1e2: bl 0x0001f17c +sp 0801e338, lr 000369f0, pc 0001f17c, insn e59f1210: ldr r1, [pc, #528] ; 0x0001f394 +sp 0801e338, lr 000369f0, pc 0001f180, insn e7910100: ldr r0, [r1, r0, lsl #2] +sp 0801e338, lr 000369f0, pc 0001f184, insn e280f000: add pc, r0, #0 ; 0x0 +sp 0801e338, lr 000369f0, pc 00005568, insn e59f107c: ldr r1, [pc, #124] ; 0x000055ec +sp 0801e338, lr 000369f0, pc 0000556c, insn e5910000: ldr r0, [r1] +sp 0801e338, lr 000369f0, pc 00005570, insn e3100002: tst r0, #2 ; 0x2 +sp 0801e338, lr 000369f0, pc 00005574, insn 0a000004: beq 0x0000558c +sp 0801e338, lr 000369f0, pc 00005578, insn e5910000: ldr r0, [r1] +sp 0801e338, lr 000369f0, pc 0000557c, insn e3100004: tst r0, #4 ; 0x4 +sp 0801e338, lr 000369f0, pc 00005580, insn 0a000001: beq 0x0000558c +sp 0801e338, lr 000369f0, pc 00005584, insn e3a00000: mov r0, #0 ; 0x0 +sp 0801e338, lr 000369f0, pc 00005588, insn e1a0f00e: mov pc, lr +sp 0801e338, lr 000369f0, pc 000369f0, insn ea000018: b 0x00036a58 +sp 0801e338, lr 000369f0, pc 00036a58, insn ebffff76: bl 0x00036838 +sp 0801e338, lr 00036a5c, pc 00036838, insn e92d4003: stmdb sp!, {r0, r1, lr} +sp 0801e32c, lr 00036a5c, pc 0003683c, insn e59fe2c0: ldr lr, [pc, #704] ; 0x00036b04 +sp 0801e32c, lr 08002368, pc 00036840, insn e59ee000: ldr lr, [lr] +sp 0801e32c, lr 080024d8, pc 00036844, insn e33e0000: teq lr, #0 ; 0x0 +sp 0801e32c, lr 080024d8, pc 00036848, insn 1bffffee: blne 0x00036808 +sp 0801e32c, lr 0003684c, pc 00036808, insn e92d4000: stmdb sp!, {lr} +sp 0801e328, lr 0003684c, pc 0003680c, insn e59fe2f0: ldr lr, [pc, #752] ; 0x00036b04 +sp 0801e328, lr 08002368, pc 00036810, insn e59ee000: ldr lr, [lr] +sp 0801e328, lr 080024d8, pc 00036814, insn e28ee028: add lr, lr, #40 ; 0x28 +sp 0801e328, lr 08002500, pc 00036818, insn e8ce7fff: stmia lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^ +sp 0801e328, lr 08002500, pc 0003681c, insn e8bd8000: ldmia sp!, {pc} +sp 0801e32c, lr 08002500, pc 0003684c, insn e59f02b4: ldr r0, [pc, #692] ; 0x00036b08 +sp 0801e32c, lr 08002500, pc 00036850, insn e5d01000: ldrb r1, [r0] +sp 0801e32c, lr 08002500, pc 00036854, insn e3510001: cmp r1, #1 ; 0x1 +sp 0801e32c, lr 08002500, pc 00036858, insn 0a000002: beq 0x00036868 +sp 0801e32c, lr 08002500, pc 00036868, insn e59f42a0: ldr r4, [pc, #672] ; 0x00036b10 +sp 0801e32c, lr 08002500, pc 0003686c, insn e59f52a0: ldr r5, [pc, #672] ; 0x00036b14 +sp 0801e32c, lr 08002500, pc 00036870, insn e59f62a0: ldr r6, [pc, #672] ; 0x00036b18 +sp 0801e32c, lr 08002500, pc 00036874, insn e2866f40: add r6, r6, #256 ; 0x100 +sp 0801e32c, lr 08002500, pc 00036878, insn e59f829c: ldr r8, [pc, #668] ; 0x00036b1c +sp 0801e32c, lr 08002500, pc 0003687c, insn e59fa29c: ldr sl, [pc, #668] ; 0x00036b20 +sp 0801e32c, lr 08002500, pc 00036880, insn e59fb29c: ldr fp, [pc, #668] ; 0x00036b24 +sp 0801e32c, lr 08002500, pc 00036884, insn ea00000a: b 0x000368b4 +sp 0801e32c, lr 08002500, pc 000368b4, insn e5940000: ldr r0, [r4] +sp 0801e32c, lr 08002500, pc 000368b8, insn e5951000: ldr r1, [r5] +sp 0801e32c, lr 08002500, pc 000368bc, insn e1500001: cmp r0, r1 +sp 0801e32c, lr 08002500, pc 000368c0, insn 1afffff0: bne 0x00036888 +sp 0801e32c, lr 08002500, pc 000368c4, insn e5da2000: ldrb r2, [sl] +sp 0801e32c, lr 08002500, pc 000368c8, insn e3520000: cmp r2, #0 ; 0x0 +sp 0801e32c, lr 08002500, pc 000368cc, insn 0a000011: beq 0x00036918 +sp 0801e32c, lr 08002500, pc 00036918, insn e5940000: ldr r0, [r4] +sp 0801e32c, lr 08002500, pc 0003691c, insn e5951000: ldr r1, [r5] +sp 0801e32c, lr 08002500, pc 00036920, insn e1500001: cmp r0, r1 +sp 0801e32c, lr 08002500, pc 00036924, insn 1affffd7: bne 0x00036888 +sp 0801e32c, lr 08002500, pc 00036928, insn ebffffbc: bl 0x00036820 +sp 0801e32c, lr 0003692c, pc 00036820, insn e92d4000: stmdb sp!, {lr} +sp 0801e328, lr 0003692c, pc 00036824, insn e59fe2d8: ldr lr, [pc, #728] ; 0x00036b04 +sp 0801e328, lr 08002368, pc 00036828, insn e59ee000: ldr lr, [lr] +sp 0801e328, lr 080024d8, pc 0003682c, insn e28ee028: add lr, lr, #40 ; 0x28 +sp 0801e328, lr 08002500, pc 00036830, insn e8de7fff: ldmia lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^ +sp 0801e328, lr 08002500, pc 00036834, insn e8bd8000: ldmia sp!, {pc} +sp 0801e32c, lr 08002500, pc 0003692c, insn e8bd8003: ldmia sp!, {r0, r1, pc} +sp 0801e338, lr 08002500, pc 00036a5c, insn e59fe0a0: ldr lr, [pc, #160] ; 0x00036b04 +sp 0801e338, lr 08002368, pc 00036a60, insn e59ee000: ldr lr, [lr] +sp 0801e338, lr 080024d8, pc 00036a64, insn e58ed00c: str sp, [lr, #12] +sp 0801e338, lr 080024d8, pc 00036a68, insn e59fd088: ldr sp, [pc, #136] ; 0x00036af8 +sp 080004fc, lr 080024d8, pc 00036a6c, insn e92d0003: stmdb sp!, {r0, r1} +sp 080004f4, lr 080024d8, pc 00036a70, insn e59f0090: ldr r0, [pc, #144] ; 0x00036b08 +sp 080004f4, lr 080024d8, pc 00036a74, insn e5d01000: ldrb r1, [r0] +sp 080004f4, lr 080024d8, pc 00036a78, insn e2411001: sub r1, r1, #1 ; 0x1 +sp 080004f4, lr 080024d8, pc 00036a7c, insn e5c01000: strb r1, [r0] +sp 080004f4, lr 080024d8, pc 00036a80, insn e8bd0003: ldmia sp!, {r0, r1} +sp 080004fc, lr 080024d8, pc 00036a84, insn e25ff004: subs pc, pc, #4 ; 0x4 +sp 0801e338, lr 0001ebb4, pc 00036a88, insn e92d40ff: stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, lr} +sp 0801e314, lr 0001ebb4, pc 00036a8c, insn e10f0000: mrs r0, CPSR +sp 0801e314, lr 0001ebb4, pc 00036a90, insn e92d0001: stmdb sp!, {r0} +sp 0801e310, lr 0001ebb4, pc 00036a94, insn e59f408c: ldr r4, [pc, #140] ; 0x00036b28 +sp 0801e310, lr 0001ebb4, pc 00036a98, insn e59f508c: ldr r5, [pc, #140] ; 0x00036b2c +TIMER: assert TIMER2 interrupt +INTC: assert irq 12 (00001000) +INTC: vector to 0000001c +x49gp_set_idle: arm_ID 4452, idle 0 +x49gp_set_idle: arm_ID 4452, idle 0 +Exception taken: pc 00036a9c, r15: 0000001c +sp 0800077c, lr 00036aa0, pc 0000001c, insn ea00004b: b 0x00000150 +sp 0800077c, lr 00036aa0, pc 00000150, insn e24dd004: sub sp, sp, #4 ; 0x4 +sp 08000778, lr 00036aa0, pc 00000154, insn e92d0300: stmdb sp!, {r8, r9} +sp 08000770, lr 00036aa0, pc 00000158, insn e3a08680: mov r8, #134217728 ; 0x8000000 +sp 08000770, lr 00036aa0, pc 0000015c, insn e598901c: ldr r9, [r8, #28] +sp 08000770, lr 00036aa0, pc 00000160, insn e58d9008: str r9, [sp, #8] +sp 08000770, lr 00036aa0, pc 00000164, insn e8bd8300: ldmia sp!, {r8, r9, pc} +sp 0800077c, lr 00036aa0, pc 00005338, insn e92d500f: stmdb sp!, {r0, r1, r2, r3, ip, lr} +sp 08000764, lr 00036aa0, pc 0000533c, insn e3a01671: mov r1, #118489088 ; 0x7100000 +sp 08000764, lr 00036aa0, pc 00005340, insn e5910004: ldr r0, [r1, #4] +read INTC [4a000000] INTMOD [00000004] data 00001000 +sp 08000764, lr 00036aa0, pc 00005344, insn e3100d40: tst r0, #4096 ; 0x1000 +sp 08000764, lr 00036aa0, pc 00005348, insn 0a000003: beq 0x0000535c +sp 08000764, lr 00036aa0, pc 0000534c, insn e1a00001: mov r0, r1 +sp 08000764, lr 00036aa0, pc 00005350, insn e3a01d40: mov r1, #4096 ; 0x1000 +sp 08000764, lr 00036aa0, pc 00005354, insn e5801000: str r1, [r0] +write INTC [4a000000] SRCPND [00000000] data 00001000 +sp 08000764, lr 00036aa0, pc 00005358, insn ea000001: b 0x00005364 +sp 08000764, lr 00036aa0, pc 00005364, insn e59f0278: ldr r0, [pc, #632] ; 0x000055e4 +sp 08000764, lr 00036aa0, pc 00005368, insn e5900000: ldr r0, [r0] +sp 08000764, lr 00036aa0, pc 0000536c, insn e59f2274: ldr r2, [pc, #628] ; 0x000055e8 +sp 08000764, lr 00036aa0, pc 00005370, insn e5921000: ldr r1, [r2] +sp 08000764, lr 00036aa0, pc 00005374, insn e1500001: cmp r0, r1 +sp 08000764, lr 00036aa0, pc 00005378, insn 1a00000f: bne 0x000053bc +sp 08000764, lr 00036aa0, pc 0000537c, insn e3a00002: mov r0, #2 ; 0x2 +sp 08000764, lr 00036aa0, pc 00005380, insn ebfffd7f: bl 0x00004984 +sp 08000764, lr 00005384, pc 00004984, insn e3a02676: mov r2, #123731968 ; 0x7600000 +sp 08000764, lr 00005384, pc 00004988, insn e2821008: add r1, r2, #8 ; 0x8 +sp 08000764, lr 00005384, pc 0000498c, insn e3500000: cmp r0, #0 ; 0x0 +sp 08000764, lr 00005384, pc 00004990, insn 1a000003: bne 0x000049a4 +sp 08000764, lr 00005384, pc 000049a4, insn e5922008: ldr r2, [r2, #8] +read TIMER [51000000] TCON [00000008] data 00499909 +sp 08000764, lr 00005384, pc 000049a8, insn e3a03004: mov r3, #4 ; 0x4 +sp 08000764, lr 00005384, pc 000049ac, insn e0830100: add r0, r3, r0, lsl #2 +sp 08000764, lr 00005384, pc 000049b0, insn e3a03001: mov r3, #1 ; 0x1 +sp 08000764, lr 00005384, pc 000049b4, insn e1c20013: bic r0, r2, r3, lsl r0 +sp 08000764, lr 00005384, pc 000049b8, insn e5810000: str r0, [r1] +write TIMER [51000000] TCON [00000008] data 00498909 +TIMER: stop TIMER2 +sp 08000764, lr 00005384, pc 000049bc, insn eafffff7: b 0x000049a0 +sp 08000764, lr 00005384, pc 000049a0, insn e1a0f00e: mov pc, lr +sp 08000764, lr 00005384, pc 00005384, insn e59f1260: ldr r1, [pc, #608] ; 0x000055ec +sp 08000764, lr 00005384, pc 00005388, insn e3a00001: mov r0, #1 ; 0x1 +sp 08000764, lr 00005384, pc 0000538c, insn e5810000: str r0, [r1] +sp 08000764, lr 00005384, pc 00005390, insn e3a01000: mov r1, #0 ; 0x0 +sp 08000764, lr 00005384, pc 00005394, insn e3a00002: mov r0, #2 ; 0x2 +sp 08000764, lr 00005384, pc 00005398, insn ebffffc5: bl 0x000052b4 +sp 08000764, lr 0000539c, pc 000052b4, insn e92d4030: stmdb sp!, {r4, r5, lr} +sp 08000758, lr 0000539c, pc 000052b8, insn e1a03001: mov r3, r1 +sp 08000758, lr 0000539c, pc 000052bc, insn e1a02080: mov r2, r0, lsl #1 +sp 08000758, lr 0000539c, pc 000052c0, insn e3a01003: mov r1, #3 ; 0x3 +sp 08000758, lr 0000539c, pc 000052c4, insn e59fc314: ldr ip, [pc, #788] ; 0x000055e0 +sp 08000758, lr 0000539c, pc 000052c8, insn e3a05001: mov r5, #1 ; 0x1 +sp 08000758, lr 0000539c, pc 000052cc, insn e1a00015: mov r0, r5, lsl r0 +sp 08000758, lr 0000539c, pc 000052d0, insn e1a01211: mov r1, r1, lsl r2 +sp 08000758, lr 0000539c, pc 000052d4, insn e3530001: cmp r3, #1 ; 0x1 +sp 08000758, lr 0000539c, pc 000052d8, insn e3a0467a: mov r4, #127926272 ; 0x7a00000 +sp 08000758, lr 0000539c, pc 000052dc, insn e28ce008: add lr, ip, #8 ; 0x8 +sp 08000758, lr 07a00018, pc 000052e0, insn 1a000008: bne 0x00005308 +sp 08000758, lr 07a00018, pc 00005308, insn e5943018: ldr r3, [r4, #24] +read IO_PORT [56000000] GPBUP [00000018] data 000007fb +sp 08000758, lr 07a00018, pc 0000530c, insn e1c33000: bic r3, r3, r0 +sp 08000758, lr 07a00018, pc 00005310, insn e1833000: orr r3, r3, r0 +sp 08000758, lr 07a00018, pc 00005314, insn e58e3000: str r3, [lr] +write IO_PORT [56000000] GPBUP [00000018] data 000007ff +sp 08000758, lr 07a00018, pc 00005318, insn e5943010: ldr r3, [r4, #16] +read IO_PORT [56000000] GPBCON [00000010] data 00155565 +sp 08000758, lr 07a00018, pc 0000531c, insn e1c31001: bic r1, r3, r1 +sp 08000758, lr 07a00018, pc 00005320, insn e1811215: orr r1, r1, r5, lsl r2 +sp 08000758, lr 07a00018, pc 00005324, insn e58c1000: str r1, [ip] +write IO_PORT [56000000] GPBCON [00000010] data 00155555 +sp 08000758, lr 07a00018, pc 00005328, insn e5941014: ldr r1, [r4, #20] +read IO_PORT [56000000] GPBDAT [00000014] data 00000000 +sp 08000758, lr 07a00018, pc 0000532c, insn e1c10000: bic r0, r1, r0 +sp 08000758, lr 07a00018, pc 00005330, insn e5840014: str r0, [r4, #20] +write IO_PORT [56000000] GPBDAT [00000014] data 00000000 +sp 08000758, lr 07a00018, pc 00005334, insn eafffff2: b 0x00005304 +sp 08000758, lr 07a00018, pc 00005304, insn e8bd8030: ldmia sp!, {r4, r5, pc} +sp 08000764, lr 07a00018, pc 0000539c, insn e59f124c: ldr r1, [pc, #588] ; 0x000055f0 +sp 08000764, lr 07a00018, pc 000053a0, insn e591000c: ldr r0, [r1, #12] +sp 08000764, lr 07a00018, pc 000053a4, insn e3500000: cmp r0, #0 ; 0x0 +sp 08000764, lr 07a00018, pc 000053a8, insn 0a000001: beq 0x000053b4 +sp 08000764, lr 07a00018, pc 000053ac, insn e2400001: sub r0, r0, #1 ; 0x1 +sp 08000764, lr 07a00018, pc 000053b0, insn e581000c: str r0, [r1, #12] +sp 08000764, lr 07a00018, pc 000053b4, insn e8bd500f: ldmia sp!, {r0, r1, r2, r3, ip, lr} +sp 0800077c, lr 00036aa0, pc 000053b8, insn e25ef004: subs pc, lr, #4 ; 0x4 +sp 0801e310, lr 0001ebb4, pc 00036a9c, insn e59f608c: ldr r6, [pc, #140] ; 0x00036b30 +sp 0801e310, lr 0001ebb4, pc 00036aa0, insn e2867080: add r7, r6, #128 ; 0x80 +sp 0801e310, lr 0001ebb4, pc 00036aa4, insn ea000007: b 0x00036ac8 +sp 0801e310, lr 0001ebb4, pc 00036ac8, insn e5940000: ldr r0, [r4] +sp 0801e310, lr 0001ebb4, pc 00036acc, insn e5951000: ldr r1, [r5] +sp 0801e310, lr 0001ebb4, pc 00036ad0, insn e1500001: cmp r0, r1 +sp 0801e310, lr 0001ebb4, pc 00036ad4, insn 1afffff3: bne 0x00036aa8 +sp 0801e310, lr 0001ebb4, pc 00036ad8, insn e8bd0001: ldmia sp!, {r0} +sp 0801e314, lr 0001ebb4, pc 00036adc, insn e12ff000: msr CPSR_fsxc, r0 +sp 0801e314, lr 0001ebb4, pc 00036ae0, insn e8bd80ff: ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r7, pc} +sp 0801e338, lr 0001ebb4, pc 0001ebb4, insn e20000ff: and r0, r0, #255 ; 0xff +sp 0801e338, lr 0001ebb4, pc 0001ebb8, insn e8bd8008: ldmia sp!, {r3, pc} +sp 0801e340, lr 0001ebb4, pc 0001ebec, insn e3500000: cmp r0, #0 ; 0x0 +sp 0801e340, lr 0001ebb4, pc 0001ebf0, insn 0afffffc: beq 0x0001ebe8 +sp 0801e340, lr 0001ebb4, pc 0001ebe8, insn ebffffee: bl 0x0001eba8 +sp 0801e340, lr 0001ebec, pc 0001eba8, insn e92d4008: stmdb sp!, {r3, lr} +sp 0801e338, lr 0001ebec, pc 0001ebac, insn e3a0001c: mov r0, #28 ; 0x1c +sp 0801e338, lr 0001ebec, pc 0001ebb0, insn ebfffef9: bl 0x0001e79c +sp 0801e338, lr 0001ebb4, pc 0001e79c, insn ea00627b: b 0x00037190 +sp 0801e338, lr 0001ebb4, pc 00037190, insn ef000000: swi 0x00000000 +ARMul_OSHandleSWI: PC 00037198: syscall 28: args 08000a98 0000004a 00037ed4 00000000 0000162e 08003b40 00001629 +sp 080004fc, lr 00037194, pc 00000008, insn ea000035: b 0x000000e4 +sp 080004fc, lr 00037194, pc 000000e4, insn e24dd004: sub sp, sp, #4 ; 0x4 +sp 080004f8, lr 00037194, pc 000000e8, insn e92d0300: stmdb sp!, {r8, r9} +sp 080004f0, lr 00037194, pc 000000ec, insn e3a08680: mov r8, #134217728 ; 0x8000000 +sp 080004f0, lr 00037194, pc 000000f0, insn e5989008: ldr r9, [r8, #8] +sp 080004f0, lr 00037194, pc 000000f4, insn e58d9008: str r9, [sp, #8] +sp 080004f0, lr 00037194, pc 000000f8, insn e8bd8300: ldmia sp!, {r8, r9, pc} +sp 080004fc, lr 00037194, pc 000369b8, insn e94d3000: stmdb sp, {ip, sp}^ +sp 080004fc, lr 00037194, pc 000369bc, insn e59fe144: ldr lr, [pc, #324] ; 0x00036b08 +sp 080004fc, lr 08002360, pc 000369c0, insn e5dec000: ldrb ip, [lr] +sp 080004fc, lr 08002360, pc 000369c4, insn e28cc001: add ip, ip, #1 ; 0x1 +sp 080004fc, lr 08002360, pc 000369c8, insn e5cec000: strb ip, [lr] +sp 080004fc, lr 08002360, pc 000369cc, insn e91d3000: ldmdb sp, {ip, sp} +sp 0801e338, lr 08002360, pc 000369d0, insn e10fe000: mrs lr, CPSR +sp 0801e338, lr 60000093, pc 000369d4, insn e3cee0c0: bic lr, lr, #192 ; 0xc0 +sp 0801e338, lr 60000013, pc 000369d8, insn e121f00e: msr CPSR_c, lr +sp 0801e338, lr 60000013, pc 000369dc, insn e3300000: teq r0, #0 ; 0x0 +sp 0801e338, lr 60000013, pc 000369e0, insn 0a00001c: beq 0x00036a58 +sp 0801e338, lr 60000013, pc 000369e4, insn e3500064: cmp r0, #100 ; 0x64 +sp 0801e338, lr 60000013, pc 000369e8, insn aa000001: bge 0x000369f4 +sp 0801e338, lr 60000013, pc 000369ec, insn ebffa1e2: bl 0x0001f17c +sp 0801e338, lr 000369f0, pc 0001f17c, insn e59f1210: ldr r1, [pc, #528] ; 0x0001f394 +sp 0801e338, lr 000369f0, pc 0001f180, insn e7910100: ldr r0, [r1, r0, lsl #2] +sp 0801e338, lr 000369f0, pc 0001f184, insn e280f000: add pc, r0, #0 ; 0x0 +sp 0801e338, lr 000369f0, pc 00005568, insn e59f107c: ldr r1, [pc, #124] ; 0x000055ec +sp 0801e338, lr 000369f0, pc 0000556c, insn e5910000: ldr r0, [r1] +sp 0801e338, lr 000369f0, pc 00005570, insn e3100002: tst r0, #2 ; 0x2 +sp 0801e338, lr 000369f0, pc 00005574, insn 0a000004: beq 0x0000558c +sp 0801e338, lr 000369f0, pc 0000558c, insn e3a00001: mov r0, #1 ; 0x1 +sp 0801e338, lr 000369f0, pc 00005590, insn eafffffc: b 0x00005588 +sp 0801e338, lr 000369f0, pc 00005588, insn e1a0f00e: mov pc, lr +sp 0801e338, lr 000369f0, pc 000369f0, insn ea000018: b 0x00036a58 +sp 0801e338, lr 000369f0, pc 00036a58, insn ebffff76: bl 0x00036838 +sp 0801e338, lr 00036a5c, pc 00036838, insn e92d4003: stmdb sp!, {r0, r1, lr} +sp 0801e32c, lr 00036a5c, pc 0003683c, insn e59fe2c0: ldr lr, [pc, #704] ; 0x00036b04 +sp 0801e32c, lr 08002368, pc 00036840, insn e59ee000: ldr lr, [lr] +sp 0801e32c, lr 080024d8, pc 00036844, insn e33e0000: teq lr, #0 ; 0x0 +sp 0801e32c, lr 080024d8, pc 00036848, insn 1bffffee: blne 0x00036808 +sp 0801e32c, lr 0003684c, pc 00036808, insn e92d4000: stmdb sp!, {lr} +sp 0801e328, lr 0003684c, pc 0003680c, insn e59fe2f0: ldr lr, [pc, #752] ; 0x00036b04 +sp 0801e328, lr 08002368, pc 00036810, insn e59ee000: ldr lr, [lr] +sp 0801e328, lr 080024d8, pc 00036814, insn e28ee028: add lr, lr, #40 ; 0x28 +sp 0801e328, lr 08002500, pc 00036818, insn e8ce7fff: stmia lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^ +sp 0801e328, lr 08002500, pc 0003681c, insn e8bd8000: ldmia sp!, {pc} +sp 0801e32c, lr 08002500, pc 0003684c, insn e59f02b4: ldr r0, [pc, #692] ; 0x00036b08 +sp 0801e32c, lr 08002500, pc 00036850, insn e5d01000: ldrb r1, [r0] +sp 0801e32c, lr 08002500, pc 00036854, insn e3510001: cmp r1, #1 ; 0x1 +sp 0801e32c, lr 08002500, pc 00036858, insn 0a000002: beq 0x00036868 +sp 0801e32c, lr 08002500, pc 00036868, insn e59f42a0: ldr r4, [pc, #672] ; 0x00036b10 +sp 0801e32c, lr 08002500, pc 0003686c, insn e59f52a0: ldr r5, [pc, #672] ; 0x00036b14 +sp 0801e32c, lr 08002500, pc 00036870, insn e59f62a0: ldr r6, [pc, #672] ; 0x00036b18 +sp 0801e32c, lr 08002500, pc 00036874, insn e2866f40: add r6, r6, #256 ; 0x100 +sp 0801e32c, lr 08002500, pc 00036878, insn e59f829c: ldr r8, [pc, #668] ; 0x00036b1c +sp 0801e32c, lr 08002500, pc 0003687c, insn e59fa29c: ldr sl, [pc, #668] ; 0x00036b20 +sp 0801e32c, lr 08002500, pc 00036880, insn e59fb29c: ldr fp, [pc, #668] ; 0x00036b24 +sp 0801e32c, lr 08002500, pc 00036884, insn ea00000a: b 0x000368b4 +sp 0801e32c, lr 08002500, pc 000368b4, insn e5940000: ldr r0, [r4] +sp 0801e32c, lr 08002500, pc 000368b8, insn e5951000: ldr r1, [r5] +sp 0801e32c, lr 08002500, pc 000368bc, insn e1500001: cmp r0, r1 +sp 0801e32c, lr 08002500, pc 000368c0, insn 1afffff0: bne 0x00036888 +sp 0801e32c, lr 08002500, pc 000368c4, insn e5da2000: ldrb r2, [sl] +sp 0801e32c, lr 08002500, pc 000368c8, insn e3520000: cmp r2, #0 ; 0x0 +sp 0801e32c, lr 08002500, pc 000368cc, insn 0a000011: beq 0x00036918 +sp 0801e32c, lr 08002500, pc 00036918, insn e5940000: ldr r0, [r4] +sp 0801e32c, lr 08002500, pc 0003691c, insn e5951000: ldr r1, [r5] +sp 0801e32c, lr 08002500, pc 00036920, insn e1500001: cmp r0, r1 +sp 0801e32c, lr 08002500, pc 00036924, insn 1affffd7: bne 0x00036888 +sp 0801e32c, lr 08002500, pc 00036928, insn ebffffbc: bl 0x00036820 +sp 0801e32c, lr 0003692c, pc 00036820, insn e92d4000: stmdb sp!, {lr} +sp 0801e328, lr 0003692c, pc 00036824, insn e59fe2d8: ldr lr, [pc, #728] ; 0x00036b04 +sp 0801e328, lr 08002368, pc 00036828, insn e59ee000: ldr lr, [lr] +sp 0801e328, lr 080024d8, pc 0003682c, insn e28ee028: add lr, lr, #40 ; 0x28 +sp 0801e328, lr 08002500, pc 00036830, insn e8de7fff: ldmia lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^ +sp 0801e328, lr 08002500, pc 00036834, insn e8bd8000: ldmia sp!, {pc} +sp 0801e32c, lr 08002500, pc 0003692c, insn e8bd8003: ldmia sp!, {r0, r1, pc} +sp 0801e338, lr 08002500, pc 00036a5c, insn e59fe0a0: ldr lr, [pc, #160] ; 0x00036b04 +sp 0801e338, lr 08002368, pc 00036a60, insn e59ee000: ldr lr, [lr] +sp 0801e338, lr 080024d8, pc 00036a64, insn e58ed00c: str sp, [lr, #12] +sp 0801e338, lr 080024d8, pc 00036a68, insn e59fd088: ldr sp, [pc, #136] ; 0x00036af8 +sp 080004fc, lr 080024d8, pc 00036a6c, insn e92d0003: stmdb sp!, {r0, r1} +sp 080004f4, lr 080024d8, pc 00036a70, insn e59f0090: ldr r0, [pc, #144] ; 0x00036b08 +sp 080004f4, lr 080024d8, pc 00036a74, insn e5d01000: ldrb r1, [r0] +sp 080004f4, lr 080024d8, pc 00036a78, insn e2411001: sub r1, r1, #1 ; 0x1 +sp 080004f4, lr 080024d8, pc 00036a7c, insn e5c01000: strb r1, [r0] +sp 080004f4, lr 080024d8, pc 00036a80, insn e8bd0003: ldmia sp!, {r0, r1} +sp 080004fc, lr 080024d8, pc 00036a84, insn e25ff004: subs pc, pc, #4 ; 0x4 +sp 0801e338, lr 0001ebb4, pc 00036a88, insn e92d40ff: stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, lr} +sp 0801e314, lr 0001ebb4, pc 00036a8c, insn e10f0000: mrs r0, CPSR +sp 0801e314, lr 0001ebb4, pc 00036a90, insn e92d0001: stmdb sp!, {r0} +sp 0801e310, lr 0001ebb4, pc 00036a94, insn e59f408c: ldr r4, [pc, #140] ; 0x00036b28 +sp 0801e310, lr 0001ebb4, pc 00036a98, insn e59f508c: ldr r5, [pc, #140] ; 0x00036b2c +sp 0801e310, lr 0001ebb4, pc 00036a9c, insn e59f608c: ldr r6, [pc, #140] ; 0x00036b30 +sp 0801e310, lr 0001ebb4, pc 00036aa0, insn e2867080: add r7, r6, #128 ; 0x80 +sp 0801e310, lr 0001ebb4, pc 00036aa4, insn ea000007: b 0x00036ac8 +sp 0801e310, lr 0001ebb4, pc 00036ac8, insn e5940000: ldr r0, [r4] +sp 0801e310, lr 0001ebb4, pc 00036acc, insn e5951000: ldr r1, [r5] +sp 0801e310, lr 0001ebb4, pc 00036ad0, insn e1500001: cmp r0, r1 +sp 0801e310, lr 0001ebb4, pc 00036ad4, insn 1afffff3: bne 0x00036aa8 +sp 0801e310, lr 0001ebb4, pc 00036ad8, insn e8bd0001: ldmia sp!, {r0} +sp 0801e314, lr 0001ebb4, pc 00036adc, insn e12ff000: msr CPSR_fsxc, r0 +sp 0801e314, lr 0001ebb4, pc 00036ae0, insn e8bd80ff: ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r7, pc} +sp 0801e338, lr 0001ebb4, pc 0001ebb4, insn e20000ff: and r0, r0, #255 ; 0xff +sp 0801e338, lr 0001ebb4, pc 0001ebb8, insn e8bd8008: ldmia sp!, {r3, pc} +sp 0801e340, lr 0001ebb4, pc 0001ebec, insn e3500000: cmp r0, #0 ; 0x0 +sp 0801e340, lr 0001ebb4, pc 0001ebf0, insn 0afffffc: beq 0x0001ebe8 +sp 0801e340, lr 0001ebb4, pc 0001ebf4, insn e1a00004: mov r0, r4 +sp 0801e340, lr 0001ebb4, pc 0001ebf8, insn eafffff9: b 0x0001ebe4 +sp 0801e340, lr 0001ebb4, pc 0001ebe4, insn e8bd8010: ldmia sp!, {r4, pc} +sp 0801e348, lr 0001ebb4, pc 0002e928, insn e3a00000: mov r0, #0 ; 0x0 diff --git a/bitmaps/.svn/all-wcprops b/bitmaps/.svn/all-wcprops new file mode 100644 index 0000000..91fd5b6 --- /dev/null +++ b/bitmaps/.svn/all-wcprops @@ -0,0 +1,545 @@ +K 25 +svn:wc:ra_dav:version-url +V 32 +/p/x49gp/code/!svn/ver/1/bitmaps +END +tiny_braceleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_braceleft.xbm +END +tiny__i.xbm +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny__i.xbm +END +tiny_hyphen.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_hyphen.xbm +END +tiny_comma.xbm +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_comma.xbm +END +tiny_math_notequal.xbm +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_notequal.xbm +END +tiny_large_comma.xbm +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_large_comma.xbm +END +tiny_math_radical.xbm +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_radical.xbm +END +tiny_numbersign.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_numbersign.xbm +END +tiny_colon.xbm +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_colon.xbm +END +tiny_braceright.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_braceright.xbm +END +tiny_guillemotleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_guillemotleft.xbm +END +tiny_quotedbl.xbm +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_quotedbl.xbm +END +tiny_zero.xbm +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_zero.xbm +END +tiny_math_numbersign.xbm +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_numbersign.xbm +END +tiny_math_summation.xbm +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_summation.xbm +END +tiny_math_downarrowright.xbm +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_downarrowright.xbm +END +tiny_greater.xbm +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_greater.xbm +END +button_round.pix +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/button_round.pix +END +button_small.xbm +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/button_small.xbm +END +ann_io.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_io.xbm +END +tiny_xsuperior.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_xsuperior.xbm +END +tiny_twosuperior.xbm +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_twosuperior.xbm +END +tiny_math_downarrowleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_downarrowleft.xbm +END +tiny_overscore.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_overscore.xbm +END +tiny_three.xbm +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_three.xbm +END +tiny_slash.xbm +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_slash.xbm +END +ann_alpha.xbm +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_alpha.xbm +END +button_round.xbm +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/button_round.xbm +END +tiny_math_less.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_less.xbm +END +tiny_notdef.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_notdef.xbm +END +tiny_A.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_A.xbm +END +tiny_math_equal.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_equal.xbm +END +tiny_parenleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_parenleft.xbm +END +button_normal.xbm +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/1/bitmaps/button_normal.xbm +END +tiny_B.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_B.xbm +END +tiny_math_pi.xbm +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_pi.xbm +END +tiny_C.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_C.xbm +END +button_large.xbm +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/bitmaps/button_large.xbm +END +tiny_period.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_period.xbm +END +tiny_D.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_D.xbm +END +tiny_E.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_E.xbm +END +tiny_F.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_F.xbm +END +tiny_G.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_G.xbm +END +tiny_H.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_H.xbm +END +tiny_arrowright.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_arrowright.xbm +END +tiny_I.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_I.xbm +END +tiny_J.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_J.xbm +END +tiny_K.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_K.xbm +END +tiny_L.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_L.xbm +END +tiny_M.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_M.xbm +END +tiny_math_e.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_e.xbm +END +tiny_N.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_N.xbm +END +tiny_O.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_O.xbm +END +tiny_guillemotright.xbm +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_guillemotright.xbm +END +tiny_P.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_P.xbm +END +tiny_Q.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_Q.xbm +END +tiny_math_arrowright.xbm +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_arrowright.xbm +END +tiny_R.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_R.xbm +END +tiny_math_greater.xbm +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_greater.xbm +END +tiny_S.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_S.xbm +END +tiny_T.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_T.xbm +END +ann_battery.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_battery.xbm +END +tiny_U.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_U.xbm +END +tiny_V.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_V.xbm +END +tiny_W.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_W.xbm +END +tiny_equal.xbm +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_equal.xbm +END +tiny_X.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_X.xbm +END +tiny_Y.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_Y.xbm +END +tiny_Z.xbm +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_Z.xbm +END +tiny_underscore.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_underscore.xbm +END +tiny_ampersand.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_ampersand.xbm +END +button_tiny.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/button_tiny.xbm +END +ann_busy.xbm +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_busy.xbm +END +tiny_math_arrowleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_arrowleft.xbm +END +tiny_math_integral.xbm +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_integral.xbm +END +tiny_math_x.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_x.xbm +END +tiny_math_y.xbm +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_y.xbm +END +ann_left.xbm +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_left.xbm +END +tiny_math_greaterequal.xbm +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_greaterequal.xbm +END +tiny_math_partialdiff.xbm +K 25 +svn:wc:ra_dav:version-url +V 58 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_partialdiff.xbm +END +tiny_math_infinity.xbm +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_infinity.xbm +END +tiny_parenright.xbm +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_parenright.xbm +END +tiny_arrowleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_arrowleft.xbm +END +tiny_less.xbm +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_less.xbm +END +ann_right.xbm +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/bitmaps/ann_right.xbm +END +tiny_math_lessequal.xbm +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_math_lessequal.xbm +END +tiny_bracketright.xbm +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_bracketright.xbm +END +tiny_two.xbm +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_two.xbm +END +tiny_one.xbm +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_one.xbm +END +tiny_bracketleft.xbm +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/1/bitmaps/tiny_bracketleft.xbm +END diff --git a/bitmaps/.svn/entries b/bitmaps/.svn/entries new file mode 100644 index 0000000..a45961b --- /dev/null +++ b/bitmaps/.svn/entries @@ -0,0 +1,3091 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/bitmaps +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tiny_braceleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +6a96ca03ae4d3131ae52b9ec2a8df2c1 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +230 + +tiny__i.xbm +file + + + + +2013-08-23T00:54:47.000000Z +e45172ee6d333e4d51d3a3952dcc9456 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_hyphen.xbm +file + + + + +2013-08-23T00:54:47.000000Z +02b721c95ca75c341d95fcbb796a6e4c +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +185 + +tiny_comma.xbm +file + + + + +2013-08-23T00:54:47.000000Z +427fb7c5c7f62bb831d531023236b266 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +174 + +tiny_math_notequal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +7c6f9077263882d4c7d3f639e28ac981 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +244 + +tiny_large_comma.xbm +file + + + + +2013-08-23T00:54:47.000000Z +f9c5465b96c7f134416587673b0fe580 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +221 + +tiny_math_radical.xbm +file + + + + +2013-08-23T00:54:47.000000Z +e6bc9c176bf8289c8a2a160c20c20dfe +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +258 + +tiny_numbersign.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a3110308b1ebef44c8facd04915ec313 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +217 + +tiny_colon.xbm +file + + + + +2013-08-23T00:54:47.000000Z +bd62ab99812302fa0bf412cb33e31c9f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +191 + +tiny_braceright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +2a70fe7d34d3b1705c1c550d5e7097be +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +235 + +tiny_guillemotleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +250bf68b6a3ba4d65843c8a093dbbdcc +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +269 + +tiny_quotedbl.xbm +file + + + + +2013-08-23T00:54:47.000000Z +0e9aed0029bebe338cd135b0cc9015e3 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +213 + +tiny_zero.xbm +file + + + + +2013-08-23T00:54:47.000000Z +05dddea7641296e8fe9c68839f4333bf +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +193 + +tiny_math_numbersign.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a0a8c518a2d57279b1d26339e1882b83 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +306 + +tiny_math_summation.xbm +file + + + + +2013-08-23T00:54:47.000000Z +5174f3a9d0384d92876c174101b6dcc4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +255 + +tiny_math_downarrowright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +9f2b6bea47636d415a09e8e822796b83 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +323 + +tiny_greater.xbm +file + + + + +2013-08-23T00:54:47.000000Z +c25726fc89e3fb76af461f8915c429b4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +208 + +button_round.pix +file + + + + +2013-08-23T00:54:47.000000Z +f15f0737c0a09735505fce818dbb11bb +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +10070 + +button_small.xbm +file + + + + +2013-08-23T00:54:47.000000Z +4c26a830d99646aa716fee86b517d6f5 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +983 + +ann_io.xbm +file + + + + +2013-08-23T00:54:47.000000Z +b24a7a59cb19b584bdbfac87d01d76a8 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +239 + +tiny_xsuperior.xbm +file + + + + +2013-08-23T00:54:47.000000Z +609f8d464b3ed9316aec849c808cde01 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +230 + +tiny_twosuperior.xbm +file + + + + +2013-08-23T00:54:47.000000Z +fd65cd07c1144c654a97a23efd4f7a76 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +240 + +tiny_math_downarrowleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +cd8a369fbf3d1deda3eaf7d99b2d76ce +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +318 + +tiny_overscore.xbm +file + + + + +2013-08-23T00:54:47.000000Z +e9c53c81284ecfa8adb417e0c4d141b7 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +230 + +tiny_three.xbm +file + + + + +2013-08-23T00:54:47.000000Z +c7ae04ce1e55c19e2e1b54a1f4fdc942 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +198 + +tiny_slash.xbm +file + + + + +2013-08-23T00:54:47.000000Z +86d8e5949fb643f6ab346e52cb07f9db +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +198 + +ann_alpha.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a69e91c81fb2cf254290833e5b25facc +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +248 + +button_round.xbm +file + + + + +2013-08-23T00:54:47.000000Z +6518ef3935067e1f6a29da6d36f7ebd7 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1139 + +tiny_math_less.xbm +file + + + + +2013-08-23T00:54:47.000000Z +8935056ad75a52e9f7ecf626d199ffc1 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +218 + +tiny_notdef.xbm +file + + + + +2013-08-23T00:54:47.000000Z +f8ddf3eea89729fbdf557b9e16ef1044 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +191 + +tiny_A.xbm +file + + + + +2013-08-23T00:54:47.000000Z +d115248bf9d36052d64e8952238d83f3 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_math_equal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +7e20ed3eaf621d49c87da739d4824d8a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +217 + +button_normal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +c64b706e97d20ef524a024a49c03d966 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1160 + +tiny_parenleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +bb48568441a7b0d9e69874a885bf537a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +230 + +tiny_B.xbm +file + + + + +2013-08-23T00:54:47.000000Z +71bd5b0ecad09a679c3a8d3fccdc05f6 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_math_pi.xbm +file + + + + +2013-08-23T00:54:47.000000Z +7c9e701a58a036fa12cab9a591b84fd6 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +238 + +tiny_C.xbm +file + + + + +2013-08-23T00:54:47.000000Z +aaf99e9138ecc75faedfadd60d98226c +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +button_large.xbm +file + + + + +2013-08-23T00:54:47.000000Z +b201374266ab1b3fe5b6595ff92d01da +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1307 + +tiny_period.xbm +file + + + + +2013-08-23T00:54:47.000000Z +c765fa4ea7a16850aba7935fbc11118a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +173 + +tiny_D.xbm +file + + + + +2013-08-23T00:54:47.000000Z +ce07d0dc51abdea43eb72f3b7085ceea +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_E.xbm +file + + + + +2013-08-23T00:54:47.000000Z +26e0735e3b882e183a27963793cd4140 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_F.xbm +file + + + + +2013-08-23T00:54:47.000000Z +4961173732dc639e4c082eb068227541 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_G.xbm +file + + + + +2013-08-23T00:54:47.000000Z +81572038798aa20853ae863dd95c54e9 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_H.xbm +file + + + + +2013-08-23T00:54:47.000000Z +2b4113578593f6d7c28a328b8a0611e4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_arrowright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +77a9645449129d773a378b26429f0e3b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +210 + +tiny_I.xbm +file + + + + +2013-08-23T00:54:47.000000Z +1de086b1f2322748816e03937933423b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_J.xbm +file + + + + +2013-08-23T00:54:47.000000Z +ed255186f2eefde7b621cf7e9f0b2299 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_K.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a65402d6bed8531560cf33b70cd92e22 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_L.xbm +file + + + + +2013-08-23T00:54:47.000000Z +3b628d5abd97e8cb7a9f960b509bc601 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_M.xbm +file + + + + +2013-08-23T00:54:47.000000Z +aac0dc403d21ccbc230d153523506ff5 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_math_e.xbm +file + + + + +2013-08-23T00:54:47.000000Z +aec00d703dbc898019a71f724a4546af +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +197 + +tiny_N.xbm +file + + + + +2013-08-23T00:54:47.000000Z +f110f872da1081193af100a0bb248229 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_O.xbm +file + + + + +2013-08-23T00:54:47.000000Z +7348b768df5cedc854c561a9ce12de69 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_guillemotright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +68a9cf18f73ec3a14abc7cc7c466764f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +274 + +tiny_P.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a9789b1b6f5e43ab1bfb6607f29f11e8 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_Q.xbm +file + + + + +2013-08-23T00:54:47.000000Z +ee8b504d1969c72096ae64719397c3d8 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_math_arrowright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +d9d647b0b038378ce4a9dd97d468e7c7 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +279 + +tiny_R.xbm +file + + + + +2013-08-23T00:54:47.000000Z +224a2bb0fb66ea7963beb3afa8405a50 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_math_greater.xbm +file + + + + +2013-08-23T00:54:47.000000Z +47acdca9158d3cf5e04cf4202fead77f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +233 + +tiny_S.xbm +file + + + + +2013-08-23T00:54:47.000000Z +10307996f827bd06a19345c4d2074dc4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_T.xbm +file + + + + +2013-08-23T00:54:47.000000Z +e23a0eb281304a2e457c151cb3397af7 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +ann_battery.xbm +file + + + + +2013-08-23T00:54:47.000000Z +917cf2439a9f9d878b6d5eedc40aad13 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +254 + +tiny_U.xbm +file + + + + +2013-08-23T00:54:47.000000Z +ffc96f4ed1390dd3c736a04b6a62be62 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_V.xbm +file + + + + +2013-08-23T00:54:47.000000Z +304163b43679e4dfc5df7fc9293285bc +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_W.xbm +file + + + + +2013-08-23T00:54:47.000000Z +25c909c38cfdb595e1ce2ea2bd307efc +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_equal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +d57654dc8b7338e3bfa24239a10951c1 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +186 + +tiny_X.xbm +file + + + + +2013-08-23T00:54:47.000000Z +ba7244aa01ff8b65616236adedd5f491 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_Y.xbm +file + + + + +2013-08-23T00:54:47.000000Z +4775998ea1125793b35a6bb2e109b3b4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_Z.xbm +file + + + + +2013-08-23T00:54:47.000000Z +eb7ace0d75d226e0f37eb2f04821724d +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +178 + +tiny_underscore.xbm +file + + + + +2013-08-23T00:54:47.000000Z +e8936ec5f80e2e66bd33180c82ce26ae +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +199 + +tiny_ampersand.xbm +file + + + + +2013-08-23T00:54:47.000000Z +161d44f473663d54602232e99d35f2f6 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +218 + +button_tiny.xbm +file + + + + +2013-08-23T00:54:47.000000Z +2eab65dd0f188474e4f4e3602ad506cc +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +794 + +ann_busy.xbm +file + + + + +2013-08-23T00:54:47.000000Z +eb8778604ac87bb01780633e4162cbda +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +245 + +tiny_math_arrowleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +feeb8b82ea001df3a98de1f16c130c2d +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +274 + +tiny_math_integral.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a5be082029e753d65b85798c82d11bc4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +320 + +tiny_math_x.xbm +file + + + + +2013-08-23T00:54:47.000000Z +4e37ae052a1ae3ae3f3394a9924925d0 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +197 + +tiny_math_y.xbm +file + + + + +2013-08-23T00:54:47.000000Z +90f36c96ecc01f2c7fd2cbea59c2cd4a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +215 + +ann_left.xbm +file + + + + +2013-08-23T00:54:47.000000Z +bed7766441991ca46073affa4027afaa +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +245 + +tiny_math_greaterequal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +00bb2380cab2e1263aae461aee640cd8 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +264 + +tiny_math_partialdiff.xbm +file + + + + +2013-08-23T00:54:47.000000Z +fec532a68b1e04cf43ecb2d941719b6b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +259 + +tiny_math_infinity.xbm +file + + + + +2013-08-23T00:54:47.000000Z +748f10ba192dea564bd8f0dd7f94c9a4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +256 + +CVS +dir + +tiny_parenright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +775c932938d28cea7494a65276181110 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +235 + +tiny_arrowleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +102e92dc1ba66a16b5ac9fd2c916c583 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +205 + +tiny_less.xbm +file + + + + +2013-08-23T00:54:47.000000Z +dc000d556138b58661bfb24e68752d95 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +193 + +ann_right.xbm +file + + + + +2013-08-23T00:54:47.000000Z +08ef6dc67604a8b5429d97abbcb59eb1 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +248 + +tiny_math_lessequal.xbm +file + + + + +2013-08-23T00:54:47.000000Z +d423d39e18e87067c3f4cc1ab7063584 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +249 + +tiny_bracketright.xbm +file + + + + +2013-08-23T00:54:47.000000Z +996b4b228fb1f8df4357b6800e63dc53 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +245 + +tiny_two.xbm +file + + + + +2013-08-23T00:54:47.000000Z +4653e8359d0e1ffbd8a1ed4f30c7d183 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +188 + +tiny_one.xbm +file + + + + +2013-08-23T00:54:47.000000Z +32b5178b5420d3268d640a62c8080604 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +188 + +tiny_bracketleft.xbm +file + + + + +2013-08-23T00:54:47.000000Z +a9ab178a25c65a8adab75bbb1376a4c0 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +240 + diff --git a/bitmaps/.svn/text-base/ann_alpha.xbm.svn-base b/bitmaps/.svn/text-base/ann_alpha.xbm.svn-base new file mode 100644 index 0000000..e7cfcea --- /dev/null +++ b/bitmaps/.svn/text-base/ann_alpha.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_alpha_width 15 +#define ann_alpha_height 12 +static unsigned char ann_alpha_bits[] = { + 0xe0, 0x03, 0x18, 0x44, 0x0c, 0x4c, 0x06, 0x2c, 0x07, 0x2c, 0x07, 0x1c, + 0x07, 0x0c, 0x07, 0x0c, 0x07, 0x0e, 0x0e, 0x4d, 0xf8, 0x38, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/ann_battery.xbm.svn-base b/bitmaps/.svn/text-base/ann_battery.xbm.svn-base new file mode 100644 index 0000000..b4c6a45 --- /dev/null +++ b/bitmaps/.svn/text-base/ann_battery.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_battery_width 15 +#define ann_battery_height 12 +static unsigned char ann_battery_bits[] = { + 0x04, 0x10, 0x02, 0x20, 0x12, 0x24, 0x09, 0x48, 0xc9, 0x49, 0xc9, 0x49, + 0xc9, 0x49, 0x09, 0x48, 0x12, 0x24, 0x02, 0x20, 0x04, 0x10, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/ann_busy.xbm.svn-base b/bitmaps/.svn/text-base/ann_busy.xbm.svn-base new file mode 100644 index 0000000..1856111 --- /dev/null +++ b/bitmaps/.svn/text-base/ann_busy.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_busy_width 15 +#define ann_busy_height 12 +static unsigned char ann_busy_bits[] = { + 0xfc, 0x1f, 0x08, 0x08, 0x08, 0x08, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, + 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0xc8, 0x09, 0xe8, 0x0b, 0xfc, 0x1f}; diff --git a/bitmaps/.svn/text-base/ann_io.xbm.svn-base b/bitmaps/.svn/text-base/ann_io.xbm.svn-base new file mode 100644 index 0000000..0c4536d --- /dev/null +++ b/bitmaps/.svn/text-base/ann_io.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_io_width 15 +#define ann_io_height 12 +static unsigned char ann_io_bits[] = { + 0x0c, 0x00, 0x1e, 0x00, 0x33, 0x0c, 0x61, 0x18, 0xcc, 0x30, 0xfe, 0x7f, + 0xfe, 0x7f, 0xcc, 0x30, 0x61, 0x18, 0x33, 0x0c, 0x1e, 0x00, 0x0c, 0x00}; diff --git a/bitmaps/.svn/text-base/ann_left.xbm.svn-base b/bitmaps/.svn/text-base/ann_left.xbm.svn-base new file mode 100644 index 0000000..604b9d5 --- /dev/null +++ b/bitmaps/.svn/text-base/ann_left.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_left_width 15 +#define ann_left_height 12 +static unsigned char ann_left_bits[] = { + 0xfe, 0x3f, 0xff, 0x7f, 0x9f, 0x7f, 0xcf, 0x7f, 0xe7, 0x7f, 0x03, 0x78, + 0x03, 0x70, 0xe7, 0x73, 0xcf, 0x73, 0x9f, 0x73, 0xff, 0x73, 0xfe, 0x33}; diff --git a/bitmaps/.svn/text-base/ann_right.xbm.svn-base b/bitmaps/.svn/text-base/ann_right.xbm.svn-base new file mode 100644 index 0000000..bd9bd6f --- /dev/null +++ b/bitmaps/.svn/text-base/ann_right.xbm.svn-base @@ -0,0 +1,5 @@ +#define ann_right_width 15 +#define ann_right_height 12 +static unsigned char ann_right_bits[] = { + 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7c, 0xff, 0x79, 0xff, 0x73, 0x0f, 0x60, + 0x07, 0x60, 0xe7, 0x73, 0xe7, 0x79, 0xe7, 0x7c, 0xe7, 0x7f, 0xe6, 0x3f}; diff --git a/bitmaps/.svn/text-base/button_large.xbm.svn-base b/bitmaps/.svn/text-base/button_large.xbm.svn-base new file mode 100644 index 0000000..11570f8 --- /dev/null +++ b/bitmaps/.svn/text-base/button_large.xbm.svn-base @@ -0,0 +1,19 @@ +#define button_large_width 46 +#define button_large_height 32 +static unsigned char button_large_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/button_normal.xbm.svn-base b/bitmaps/.svn/text-base/button_normal.xbm.svn-base new file mode 100644 index 0000000..e979828 --- /dev/null +++ b/bitmaps/.svn/text-base/button_normal.xbm.svn-base @@ -0,0 +1,17 @@ +#define button_normal_width 46 +#define button_normal_height 28 +static unsigned char button_normal_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/button_round.pix.svn-base b/bitmaps/.svn/text-base/button_round.pix.svn-base new file mode 100644 index 0000000..e25abb9 --- /dev/null +++ b/bitmaps/.svn/text-base/button_round.pix.svn-base @@ -0,0 +1,157 @@ +/* GdkPixbuf RGBA C-Source image dump */ + +#ifdef __SUNPRO_C +#pragma align 4 (button_round) +#endif +#ifdef __GNUC__ +static const guint8 button_round[] __attribute__ ((__aligned__ (4))) = +#else +static const guint8 button_round[] = +#endif +{ "" + /* Pixbuf magic (0x47646b50) */ + "GdkP" + /* length: header (24) + pixel_data (4356) */ + "\0\0\21\34" + /* pixdata_type (0x1010002) */ + "\1\1\0\2" + /* rowstride (132) */ + "\0\0\0\204" + /* width (33) */ + "\0\0\0!" + /* height (33) */ + "\0\0\0!" + /* pixel_data: */ + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\255\0\0\0\244\0\0\0\232\0\0\0\232" + "\0\0\0\232\0\0\0\244\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\247\0\0\0\215\0\0\0|\0\0\0o\0\0\0_\0\0\0Z\0\0\0Z\0\0" + "\0_\0\0\0f\0\0\0o\0\0\0\201\0\0\0\225\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0" + "\0\211\0\0\0h\0\0\0W\0\0\0D\0\0\0:\0\0\0""1\0\0\0/\0\0\0,\0\0\0/\0\0" + "\0""4\0\0\0:\0\0\0H\0\0\0Z\0\0\0r\0\0\0\215\0\0\0\255\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0o\0\0\0R\0\0\0:\0" + "\0\0*\0\0\0!\0\0\0\34\0\0\0\27\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\27\0" + "\0\0\35\0\0\0#\0\0\0/\0\0\0A\0\0\0W\0\0\0|\0\0\0\244\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\261\0\0\0\215\0\0\0_\0\0\0D\0\0\0,\0\0\0\35\0\0\0" + "\26\0\0\0\21\0\0\0\16\0\0\0\15\0\0\0\13\0\0\0\13\0\0\0\13\0\0\0\15\0" + "\0\0\16\0\0\0\22\0\0\0\27\0\0\0\37\0\0\0""1\0\0\0K\0\0\0h\0\0\0\225\0" + "\0\0\273\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\211\0\0\0_\0\0\0:\0\0\0#\0\0\0\27\0\0\0\20" + "\0\0\0\14\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\6\0\0\0\6\0" + "\0\0\7\0\0\0\11\0\0\0\15\0\0\0\22\0\0\0\31\0\0\0(\0\0\0D\0\0\0h\0\0\0" + "\225\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\222\0\0\0_\0\0\0:\0\0\0!\0\0\0\24\0\0\0\15\0\0\0\11\0" + "\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0" + "\4\0\0\0\5\0\0\0\6\0\0\0\11\0\0\0\17\0\0\0\27\0\0\0&\0\0\0D\0\0\0o\0" + "\0\0\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\244\0\0\0o\0\0\0A\0\0\0#\0\0\0\24\0\0\0\15\0\0\0\10\0\0\0\5\0\0\0" + "\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0" + "\0\0\3\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0\16\0\0\0\27\0\0\0*\0\0\0K\0\0\0" + "|\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\211" + "\0\0\0O\0\0\0*\0\0\0\27\0\0\0\15\0\0\0\10\0\0\0\5\0\0\0\4\0\0\0\3\0\0" + "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2" + "\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\10\0\0\0\17\0\0\0\32\0\0\0""1\0\0\0_\0" + "\0\0\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\244\0\0\0f\0\0" + "\0:\0\0\0\35\0\0\0\20\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0" + "\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0" + "\0\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\12\0\0\0\22\0\0\0!\0\0\0A\0\0\0" + "r\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\211\0\0\0R\0\0\0(\0" + "\0\0\24\0\0\0\13\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2" + "\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\7\0\0\0\15\0\0\0\31\0\0\0""1\0\0\0_\0" + "\0\0\225\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0y\0\0\0A\0\0\0\37\0\0\0" + "\20\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\2\0\0\0\3\0\0\0\5\0\0\0\12\0\0\0\23\0\0\0&\0\0\0O\0\0\0\211" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0f\0\0\0""4\0\0\0\31\0\0\0\15" + "\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\10\0\0\0\17\0\0\0\37\0\0\0A\0\0\0y\0\0" + "\0\261\0\0\0\0\0\0\0\0\0\0\0\232\0\0\0_\0\0\0/\0\0\0\27\0\0\0\14\0\0" + "\0\6\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\32\0\0\0""7\0\0\0h\0\0\0" + "\255\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0W\0\0\0*\0\0\0\24\0\0\0\12\0\0\0" + "\5\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\2\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0f\0\0\0\244" + "\0\0\0\0\0\0\0\0\0\0\0\222\0\0\0R\0\0\0(\0\0\0\23\0\0\0\11\0\0\0\5\0" + "\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0" + "\0\0\2\0\0\0\4\0\0\0\6\0\0\0\14\0\0\0\27\0\0\0""1\0\0\0_\0\0\0\244\0" + "\0\0\0\0\0\0\0\0\0\0\225\0\0\0W\0\0\0*\0\0\0\24\0\0\0\12\0\0\0\5\0\0" + "\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0f\0\0\0\244\0\0" + "\0\0\0\0\0\0\0\0\0\232\0\0\0_\0\0\0/\0\0\0\26\0\0\0\13\0\0\0\6\0\0\0" + "\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0" + "\3\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\32\0\0\0""7\0\0\0h\0\0\0\255\0\0\0" + "\0\0\0\0\0\0\0\0\244\0\0\0f\0\0\0""4\0\0\0\31\0\0\0\15\0\0\0\6\0\0\0" + "\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0" + "\3\0\0\0\4\0\0\0\10\0\0\0\17\0\0\0\37\0\0\0A\0\0\0r\0\0\0\261\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0y\0\0\0A\0\0\0\37\0\0\0\20\0\0\0\10\0\0\0\5\0\0" + "\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0" + "\0\5\0\0\0\12\0\0\0\23\0\0\0&\0\0\0O\0\0\0\211\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\211\0\0\0R\0\0\0(\0\0\0\24\0\0\0\13\0\0\0\6\0\0\0\4" + "\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\7" + "\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0_\0\0\0\225\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\244\0\0\0f\0\0\0""7\0\0\0\35\0\0\0\20\0\0\0\10\0\0\0\5" + "\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\12" + "\0\0\0\23\0\0\0!\0\0\0D\0\0\0r\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\211\0\0\0O\0\0\0*\0\0\0\27\0\0\0\15\0\0\0\10\0\0\0" + "\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0" + "\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\10\0\0\0\17\0\0" + "\0\32\0\0\0""1\0\0\0_\0\0\0\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\244\0\0\0o\0\0\0D\0\0\0#\0\0\0\24\0\0\0\15\0\0\0\7\0" + "\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0" + "\2\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0\16\0\0\0\27\0\0\0*" + "\0\0\0K\0\0\0|\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\222\0\0\0_\0\0\0:\0\0\0!\0\0\0\24\0\0\0\15\0\0\0\11" + "\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0" + "\0\4\0\0\0\5\0\0\0\6\0\0\0\12\0\0\0\17\0\0\0\27\0\0\0&\0\0\0D\0\0\0h" + "\0\0\0\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\215\0\0\0_\0\0\0>\0\0\0#\0\0\0\27\0\0\0\20\0\0\0" + "\14\0\0\0\11\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\6\0\0\0\6\0\0\0\7" + "\0\0\0\11\0\0\0\15\0\0\0\22\0\0\0\32\0\0\0*\0\0\0D\0\0\0h\0\0\0\225\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\261\0\0\0\215\0\0\0_\0\0\0D\0\0\0*\0\0\0\35\0\0\0\26" + "\0\0\0\21\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\12\0\0\0\13\0\0\0\15\0\0\0" + "\17\0\0\0\22\0\0\0\27\0\0\0\37\0\0\0""1\0\0\0K\0\0\0o\0\0\0\225\0\0\0" + "\273\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0r\0\0\0R\0\0\0:\0\0\0" + "*\0\0\0\37\0\0\0\32\0\0\0\27\0\0\0\26\0\0\0\26\0\0\0\27\0\0\0\31\0\0" + "\0\35\0\0\0#\0\0\0/\0\0\0A\0\0\0Z\0\0\0y\0\0\0\244\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0\211\0\0\0h\0\0\0R" + "\0\0\0D\0\0\0:\0\0\0""1\0\0\0/\0\0\0,\0\0\0/\0\0\0""4\0\0\0:\0\0\0H\0" + "\0\0Z\0\0\0r\0\0\0\215\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0\215\0\0\0|\0" + "\0\0o\0\0\0f\0\0\0_\0\0\0_\0\0\0_\0\0\0f\0\0\0o\0\0\0\201\0\0\0\225\0" + "\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\255\0" + "\0\0\244\0\0\0\232\0\0\0\232\0\0\0\232\0\0\0\244\0\0\0\255\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0"}; + + diff --git a/bitmaps/.svn/text-base/button_round.xbm.svn-base b/bitmaps/.svn/text-base/button_round.xbm.svn-base new file mode 100644 index 0000000..f0d3292 --- /dev/null +++ b/bitmaps/.svn/text-base/button_round.xbm.svn-base @@ -0,0 +1,17 @@ +#define button_round_width 33 +#define button_round_height 33 +static unsigned char button_round_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0xfc, + 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x80, 0xff, 0xff, 0x03, + 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0xf0, + 0xff, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, + 0x3f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, + 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, + 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, + 0xff, 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, + 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, + 0xf8, 0xff, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00, 0xe0, 0xff, + 0xff, 0x0f, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x80, 0xff, 0xff, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, + 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/button_small.xbm.svn-base b/bitmaps/.svn/text-base/button_small.xbm.svn-base new file mode 100644 index 0000000..e3508d3 --- /dev/null +++ b/bitmaps/.svn/text-base/button_small.xbm.svn-base @@ -0,0 +1,15 @@ +#define button_small_width 36 +#define button_small_height 28 +static unsigned char button_small_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0xff, + 0x03, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, + 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfc, 0xff, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/button_tiny.xbm.svn-base b/bitmaps/.svn/text-base/button_tiny.xbm.svn-base new file mode 100644 index 0000000..39d0abb --- /dev/null +++ b/bitmaps/.svn/text-base/button_tiny.xbm.svn-base @@ -0,0 +1,13 @@ +#define button_tiny_width 36 +#define button_tiny_height 22 +static unsigned char button_tiny_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0xff, 0x03, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, + 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfc, + 0xff, 0xff, 0xff, 0x03, 0xf8, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_A.xbm.svn-base b/bitmaps/.svn/text-base/tiny_A.xbm.svn-base new file mode 100644 index 0000000..cd0e0d2 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_A.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_A_width 5 +#define tiny_A_height 7 +#define tiny_A_x_hot 0 +#define tiny_A_y_hot 6 +static unsigned char tiny_A_bits[] = { + 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_B.xbm.svn-base b/bitmaps/.svn/text-base/tiny_B.xbm.svn-base new file mode 100644 index 0000000..3fa73c1 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_B.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_B_width 5 +#define tiny_B_height 7 +#define tiny_B_x_hot 0 +#define tiny_B_y_hot 6 +static unsigned char tiny_B_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07}; diff --git a/bitmaps/.svn/text-base/tiny_C.xbm.svn-base b/bitmaps/.svn/text-base/tiny_C.xbm.svn-base new file mode 100644 index 0000000..bd10b3e --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_C.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_C_width 5 +#define tiny_C_height 7 +#define tiny_C_x_hot 0 +#define tiny_C_y_hot 6 +static unsigned char tiny_C_bits[] = { + 0x06, 0x09, 0x01, 0x01, 0x01, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_D.xbm.svn-base b/bitmaps/.svn/text-base/tiny_D.xbm.svn-base new file mode 100644 index 0000000..4c49bf8 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_D.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_D_width 5 +#define tiny_D_height 7 +#define tiny_D_x_hot 0 +#define tiny_D_y_hot 6 +static unsigned char tiny_D_bits[] = { + 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07}; diff --git a/bitmaps/.svn/text-base/tiny_E.xbm.svn-base b/bitmaps/.svn/text-base/tiny_E.xbm.svn-base new file mode 100644 index 0000000..ee69976 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_E.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_E_width 4 +#define tiny_E_height 7 +#define tiny_E_x_hot 0 +#define tiny_E_y_hot 6 +static unsigned char tiny_E_bits[] = { + 0x17, 0x01, 0x01, 0x03, 0x01, 0x01, 0x17}; diff --git a/bitmaps/.svn/text-base/tiny_F.xbm.svn-base b/bitmaps/.svn/text-base/tiny_F.xbm.svn-base new file mode 100644 index 0000000..1a998e7 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_F.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_F_width 4 +#define tiny_F_height 7 +#define tiny_F_x_hot 0 +#define tiny_F_y_hot 6 +static unsigned char tiny_F_bits[] = { + 0x07, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_G.xbm.svn-base b/bitmaps/.svn/text-base/tiny_G.xbm.svn-base new file mode 100644 index 0000000..e0e0814 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_G.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_G_width 6 +#define tiny_G_height 7 +#define tiny_G_x_hot 0 +#define tiny_G_y_hot 6 +static unsigned char tiny_G_bits[] = { + 0x0e, 0x11, 0x01, 0x01, 0x19, 0x11, 0x0e}; diff --git a/bitmaps/.svn/text-base/tiny_H.xbm.svn-base b/bitmaps/.svn/text-base/tiny_H.xbm.svn-base new file mode 100644 index 0000000..2efb290 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_H.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_H_width 5 +#define tiny_H_height 7 +#define tiny_H_x_hot 0 +#define tiny_H_y_hot 6 +static unsigned char tiny_H_bits[] = { + 0x09, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_I.xbm.svn-base b/bitmaps/.svn/text-base/tiny_I.xbm.svn-base new file mode 100644 index 0000000..7c85dee --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_I.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_I_width 4 +#define tiny_I_height 7 +#define tiny_I_x_hot 0 +#define tiny_I_y_hot 6 +static unsigned char tiny_I_bits[] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/.svn/text-base/tiny_J.xbm.svn-base b/bitmaps/.svn/text-base/tiny_J.xbm.svn-base new file mode 100644 index 0000000..ab7de19 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_J.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_J_width 5 +#define tiny_J_height 7 +#define tiny_J_x_hot 0 +#define tiny_J_y_hot 6 +static unsigned char tiny_J_bits[] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_K.xbm.svn-base b/bitmaps/.svn/text-base/tiny_K.xbm.svn-base new file mode 100644 index 0000000..f9563c4 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_K.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_K_width 5 +#define tiny_K_height 7 +#define tiny_K_x_hot 0 +#define tiny_K_y_hot 6 +static unsigned char tiny_K_bits[] = { + 0x09, 0x05, 0x05, 0x03, 0x05, 0x05, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_L.xbm.svn-base b/bitmaps/.svn/text-base/tiny_L.xbm.svn-base new file mode 100644 index 0000000..946b6f2 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_L.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_L_width 4 +#define tiny_L_height 7 +#define tiny_L_x_hot 0 +#define tiny_L_y_hot 6 +static unsigned char tiny_L_bits[] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07}; diff --git a/bitmaps/.svn/text-base/tiny_M.xbm.svn-base b/bitmaps/.svn/text-base/tiny_M.xbm.svn-base new file mode 100644 index 0000000..4091719 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_M.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_M_width 6 +#define tiny_M_height 7 +#define tiny_M_x_hot 0 +#define tiny_M_y_hot 6 +static unsigned char tiny_M_bits[] = { + 0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11}; diff --git a/bitmaps/.svn/text-base/tiny_N.xbm.svn-base b/bitmaps/.svn/text-base/tiny_N.xbm.svn-base new file mode 100644 index 0000000..068d682 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_N.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_N_width 5 +#define tiny_N_height 7 +#define tiny_N_x_hot 0 +#define tiny_N_y_hot 6 +static unsigned char tiny_N_bits[] = { + 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_O.xbm.svn-base b/bitmaps/.svn/text-base/tiny_O.xbm.svn-base new file mode 100644 index 0000000..4ef2d53 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_O.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_O_width 5 +#define tiny_O_height 7 +#define tiny_O_x_hot 0 +#define tiny_O_y_hot 6 +static unsigned char tiny_O_bits[] = { + 0x06, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_P.xbm.svn-base b/bitmaps/.svn/text-base/tiny_P.xbm.svn-base new file mode 100644 index 0000000..7fd19eb --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_P.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_P_width 5 +#define tiny_P_height 7 +#define tiny_P_x_hot 0 +#define tiny_P_y_hot 6 +static unsigned char tiny_P_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_Q.xbm.svn-base b/bitmaps/.svn/text-base/tiny_Q.xbm.svn-base new file mode 100644 index 0000000..4ecebc5 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_Q.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_Q_width 6 +#define tiny_Q_height 7 +#define tiny_Q_x_hot 0 +#define tiny_Q_y_hot 6 +static unsigned char tiny_Q_bits[] = { + 0x0e, 0x11, 0x11, 0x11, 0x15, 0x09, 0x16}; diff --git a/bitmaps/.svn/text-base/tiny_R.xbm.svn-base b/bitmaps/.svn/text-base/tiny_R.xbm.svn-base new file mode 100644 index 0000000..5088b22 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_R.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_R_width 5 +#define tiny_R_height 7 +#define tiny_R_x_hot 0 +#define tiny_R_y_hot 6 +static unsigned char tiny_R_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x05, 0x09, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_S.xbm.svn-base b/bitmaps/.svn/text-base/tiny_S.xbm.svn-base new file mode 100644 index 0000000..d567911 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_S.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_S_width 5 +#define tiny_S_height 7 +#define tiny_S_x_hot 0 +#define tiny_S_y_hot 6 +static unsigned char tiny_S_bits[] = { + 0x06, 0x09, 0x01, 0x06, 0x08, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_T.xbm.svn-base b/bitmaps/.svn/text-base/tiny_T.xbm.svn-base new file mode 100644 index 0000000..4cb3ea4 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_T.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_T_width 5 +#define tiny_T_height 7 +#define tiny_T_x_hot 1 +#define tiny_T_y_hot 6 +static unsigned char tiny_T_bits[] = { + 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}; diff --git a/bitmaps/.svn/text-base/tiny_U.xbm.svn-base b/bitmaps/.svn/text-base/tiny_U.xbm.svn-base new file mode 100644 index 0000000..f9df60e --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_U.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_U_width 5 +#define tiny_U_height 7 +#define tiny_U_x_hot 0 +#define tiny_U_y_hot 6 +static unsigned char tiny_U_bits[] = { + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_V.xbm.svn-base b/bitmaps/.svn/text-base/tiny_V.xbm.svn-base new file mode 100644 index 0000000..07bc1cc --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_V.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_V_width 5 +#define tiny_V_height 7 +#define tiny_V_x_hot 0 +#define tiny_V_y_hot 6 +static unsigned char tiny_V_bits[] = { + 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_W.xbm.svn-base b/bitmaps/.svn/text-base/tiny_W.xbm.svn-base new file mode 100644 index 0000000..c8a878e --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_W.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_W_width 6 +#define tiny_W_height 7 +#define tiny_W_x_hot 0 +#define tiny_W_y_hot 6 +static unsigned char tiny_W_bits[] = { + 0x11, 0x11, 0x11, 0x15, 0x15, 0x1b, 0x11}; diff --git a/bitmaps/.svn/text-base/tiny_X.xbm.svn-base b/bitmaps/.svn/text-base/tiny_X.xbm.svn-base new file mode 100644 index 0000000..82b3429 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_X.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_X_width 5 +#define tiny_X_height 7 +#define tiny_X_x_hot 0 +#define tiny_X_y_hot 6 +static unsigned char tiny_X_bits[] = { + 0x09, 0x09, 0x06, 0x06, 0x06, 0x09, 0x09}; diff --git a/bitmaps/.svn/text-base/tiny_Y.xbm.svn-base b/bitmaps/.svn/text-base/tiny_Y.xbm.svn-base new file mode 100644 index 0000000..1b51bf6 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_Y.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_Y_width 6 +#define tiny_Y_height 7 +#define tiny_Y_x_hot 0 +#define tiny_Y_y_hot 6 +static unsigned char tiny_Y_bits[] = { + 0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04}; diff --git a/bitmaps/.svn/text-base/tiny_Z.xbm.svn-base b/bitmaps/.svn/text-base/tiny_Z.xbm.svn-base new file mode 100644 index 0000000..f20296b --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_Z.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_Z_width 5 +#define tiny_Z_height 7 +#define tiny_Z_x_hot 0 +#define tiny_Z_y_hot 6 +static unsigned char tiny_Z_bits[] = { + 0x0f, 0x08, 0x04, 0x04, 0x02, 0x01, 0x0f}; diff --git a/bitmaps/.svn/text-base/tiny__i.xbm.svn-base b/bitmaps/.svn/text-base/tiny__i.xbm.svn-base new file mode 100644 index 0000000..4706d51 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny__i.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_i_width 4 +#define tiny_i_height 7 +#define tiny_i_x_hot 0 +#define tiny_i_y_hot 6 +static unsigned char tiny_i_bits[] = { + 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/.svn/text-base/tiny_ampersand.xbm.svn-base b/bitmaps/.svn/text-base/tiny_ampersand.xbm.svn-base new file mode 100644 index 0000000..86f807b --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_ampersand.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_ampersand_width 6 +#define tiny_ampersand_height 7 +#define tiny_ampersand_x_hot 0 +#define tiny_ampersand_y_hot 6 +static unsigned char tiny_ampersand_bits[] = { + 0x06, 0x09, 0x06, 0x16, 0x09, 0x09, 0x16}; diff --git a/bitmaps/.svn/text-base/tiny_arrowleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_arrowleft.xbm.svn-base new file mode 100644 index 0000000..25a8126 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_arrowleft.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_arrowleft_width 7 +#define tiny_arrowleft_height 5 +#define tiny_arrowleft_x_hot 0 +#define tiny_arrowleft_y_hot 4 +static unsigned char tiny_arrowleft_bits[] = { + 0x02, 0x3f, 0x02, 0x00, 0x00 }; diff --git a/bitmaps/.svn/text-base/tiny_arrowright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_arrowright.xbm.svn-base new file mode 100644 index 0000000..ab37763 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_arrowright.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_arrowright_width 7 +#define tiny_arrowright_height 5 +#define tiny_arrowright_x_hot 0 +#define tiny_arrowright_y_hot 4 +static unsigned char tiny_arrowright_bits[] = { + 0x10, 0x3f, 0x10, 0x00, 0x00 }; diff --git a/bitmaps/.svn/text-base/tiny_braceleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_braceleft.xbm.svn-base new file mode 100644 index 0000000..0f6ba86 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_braceleft.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_braceleft_width 4 +#define tiny_braceleft_height 9 +#define tiny_braceleft_x_hot 0 +#define tiny_braceleft_y_hot 7 +static unsigned char tiny_braceleft_bits[] = { + 0x04, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x04}; diff --git a/bitmaps/.svn/text-base/tiny_braceright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_braceright.xbm.svn-base new file mode 100644 index 0000000..2af45ee --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_braceright.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_braceright_width 4 +#define tiny_braceright_height 9 +#define tiny_braceright_x_hot 0 +#define tiny_braceright_y_hot 7 +static unsigned char tiny_braceright_bits[] = { + 0x01, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_bracketleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_bracketleft.xbm.svn-base new file mode 100644 index 0000000..f3ae7ea --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_bracketleft.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_bracketleft_width 4 +#define tiny_bracketleft_height 9 +#define tiny_bracketleft_x_hot 0 +#define tiny_bracketleft_y_hot 7 +static unsigned char tiny_bracketleft_bits[] = { + 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07}; diff --git a/bitmaps/.svn/text-base/tiny_bracketright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_bracketright.xbm.svn-base new file mode 100644 index 0000000..de4d785 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_bracketright.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_bracketright_width 4 +#define tiny_bracketright_height 9 +#define tiny_bracketright_x_hot 0 +#define tiny_bracketright_y_hot 7 +static unsigned char tiny_bracketright_bits[] = { + 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07}; diff --git a/bitmaps/.svn/text-base/tiny_colon.xbm.svn-base b/bitmaps/.svn/text-base/tiny_colon.xbm.svn-base new file mode 100644 index 0000000..0dc2622 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_colon.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_colon_width 3 +#define tiny_colon_height 6 +#define tiny_colon_x_hot 0 +#define tiny_colon_y_hot 5 +static unsigned char tiny_colon_bits[] = { + 0x03, 0x03, 0x00, 0x00, 0x03, 0x03 }; diff --git a/bitmaps/.svn/text-base/tiny_comma.xbm.svn-base b/bitmaps/.svn/text-base/tiny_comma.xbm.svn-base new file mode 100644 index 0000000..2adbc03 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_comma.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_comma_width 4 +#define tiny_comma_height 3 +#define tiny_comma_x_hot 0 +#define tiny_comma_y_hot 1 +static unsigned char tiny_comma_bits[] = { + 0x06, 0x06, 0x03}; diff --git a/bitmaps/.svn/text-base/tiny_equal.xbm.svn-base b/bitmaps/.svn/text-base/tiny_equal.xbm.svn-base new file mode 100644 index 0000000..512b5c8 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_equal.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_equal_width 5 +#define tiny_equal_height 5 +#define tiny_equal_x_hot 0 +#define tiny_equal_y_hot 4 +static unsigned char tiny_equal_bits[] = { + 0x0f, 0x00, 0x0f, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_greater.xbm.svn-base b/bitmaps/.svn/text-base/tiny_greater.xbm.svn-base new file mode 100644 index 0000000..44d9caf --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_greater.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_greater_width 5 +#define tiny_greater_height 7 +#define tiny_greater_x_hot 0 +#define tiny_greater_y_hot 6 +static unsigned char tiny_greater_bits[] = { + 0x01, 0x02, 0x04, 0x08, 0x04, 0x02, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_guillemotleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_guillemotleft.xbm.svn-base new file mode 100644 index 0000000..96fc88a --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_guillemotleft.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_guillemotleft_width 11 +#define tiny_guillemotleft_height 6 +#define tiny_guillemotleft_x_hot 0 +#define tiny_guillemotleft_y_hot 5 +static unsigned char tiny_guillemotleft_bits[] = { + 0x18, 0x03, 0xc6, 0x00, 0x21, 0x00, 0xc6, 0x00, 0x18, 0x03, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_guillemotright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_guillemotright.xbm.svn-base new file mode 100644 index 0000000..50d736e --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_guillemotright.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_guillemotright_width 11 +#define tiny_guillemotright_height 6 +#define tiny_guillemotright_x_hot 0 +#define tiny_guillemotright_y_hot 5 +static unsigned char tiny_guillemotright_bits[] = { + 0x63, 0x00, 0x8c, 0x01, 0x10, 0x02, 0x8c, 0x01, 0x63, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_hyphen.xbm.svn-base b/bitmaps/.svn/text-base/tiny_hyphen.xbm.svn-base new file mode 100644 index 0000000..4696e05 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_hyphen.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_hyphen_width 5 +#define tiny_hyphen_height 4 +#define tiny_hyphen_x_hot 0 +#define tiny_hyphen_y_hot 3 +static unsigned char tiny_hyphen_bits[] = { + 0x0f, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_large_comma.xbm.svn-base b/bitmaps/.svn/text-base/tiny_large_comma.xbm.svn-base new file mode 100644 index 0000000..f130f02 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_large_comma.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_large_comma_width 4 +#define tiny_large_comma_height 6 +#define tiny_large_comma_x_hot 0 +#define tiny_large_comma_y_hot 2 +static unsigned char tiny_large_comma_bits[] = { + 0x07, 0x07, 0x07, 0x04, 0x02, 0x01 }; diff --git a/bitmaps/.svn/text-base/tiny_less.xbm.svn-base b/bitmaps/.svn/text-base/tiny_less.xbm.svn-base new file mode 100644 index 0000000..c9ee854 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_less.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_less_width 5 +#define tiny_less_height 7 +#define tiny_less_x_hot 0 +#define tiny_less_y_hot 6 +static unsigned char tiny_less_bits[] = { + 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08}; diff --git a/bitmaps/.svn/text-base/tiny_math_arrowleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_arrowleft.xbm.svn-base new file mode 100644 index 0000000..117ee37 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_arrowleft.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_arrowleft_width 12 +#define tiny_math_arrowleft_height 6 +#define tiny_math_arrowleft_x_hot 0 +#define tiny_math_arrowleft_y_hot 5 +static unsigned char tiny_math_arrowleft_bits[] = { + 0x10, 0x00, 0x1c, 0x00, 0xff, 0x07, 0x1c, 0x00, 0x10, 0x00, 0x00, 0x00 + }; diff --git a/bitmaps/.svn/text-base/tiny_math_arrowright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_arrowright.xbm.svn-base new file mode 100644 index 0000000..5f23875 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_arrowright.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_arrowright_width 12 +#define tiny_math_arrowright_height 6 +#define tiny_math_arrowright_x_hot 0 +#define tiny_math_arrowright_y_hot 5 +static unsigned char tiny_math_arrowright_bits[] = { + 0x40, 0x00, 0xc0, 0x01, 0xff, 0x07, 0xc0, 0x01, 0x40, 0x00, 0x00, 0x00 + }; diff --git a/bitmaps/.svn/text-base/tiny_math_downarrowleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_downarrowleft.xbm.svn-base new file mode 100644 index 0000000..103f777 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_downarrowleft.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_downarrowleft_width 12 +#define tiny_math_downarrowleft_height 8 +#define tiny_math_downarrowleft_x_hot 0 +#define tiny_math_downarrowleft_y_hot 7 +static unsigned char tiny_math_downarrowleft_bits[] = { + 0x00, 0x04, 0x00, 0x04, 0x10, 0x04, 0x1c, 0x04, 0xff, 0x07, 0x1c, 0x00, + 0x10, 0x00, 0x00, 0x00 }; diff --git a/bitmaps/.svn/text-base/tiny_math_downarrowright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_downarrowright.xbm.svn-base new file mode 100644 index 0000000..bf7c8bc --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_downarrowright.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_downarrowright_width 12 +#define tiny_math_downarrowright_height 8 +#define tiny_math_downarrowright_x_hot 0 +#define tiny_math_downarrowright_y_hot 7 +static unsigned char tiny_math_downarrowright_bits[] = { + 0x01, 0x00, 0x01, 0x00, 0x41, 0x00, 0xc1, 0x01, 0xff, 0x07, 0xc0, 0x01, + 0x40, 0x00, 0x00, 0x00 }; diff --git a/bitmaps/.svn/text-base/tiny_math_e.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_e.xbm.svn-base new file mode 100644 index 0000000..1cb6fa3 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_e.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_e_width 6 +#define tiny_math_e_height 6 +#define tiny_math_e_x_hot 0 +#define tiny_math_e_y_hot 5 +static unsigned char tiny_math_e_bits[] = { + 0x0c, 0x12, 0x09, 0x07, 0x11, 0x0e}; diff --git a/bitmaps/.svn/text-base/tiny_math_equal.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_equal.xbm.svn-base new file mode 100644 index 0000000..cf30759 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_equal.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_equal_width 7 +#define tiny_math_equal_height 6 +#define tiny_math_equal_x_hot 0 +#define tiny_math_equal_y_hot 5 +static unsigned char tiny_math_equal_bits[] = { + 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_math_greater.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_greater.xbm.svn-base new file mode 100644 index 0000000..581b902 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_greater.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_greater_width 6 +#define tiny_math_greater_height 7 +#define tiny_math_greater_x_hot 0 +#define tiny_math_greater_y_hot 6 +static unsigned char tiny_math_greater_bits[] = { + 0x03, 0x0c, 0x10, 0x0c, 0x03, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_math_greaterequal.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_greaterequal.xbm.svn-base new file mode 100644 index 0000000..7675bf9 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_greaterequal.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_greaterequal_width 6 +#define tiny_math_greaterequal_height 8 +#define tiny_math_greaterequal_x_hot 0 +#define tiny_math_greaterequal_y_hot 7 +static unsigned char tiny_math_greaterequal_bits[] = { + 0x03, 0x0c, 0x10, 0x0c, 0x03, 0x30, 0x0c, 0x03}; diff --git a/bitmaps/.svn/text-base/tiny_math_infinity.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_infinity.xbm.svn-base new file mode 100644 index 0000000..ed48a6e --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_infinity.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_infinity_width 13 +#define tiny_math_infinity_height 5 +#define tiny_math_infinity_x_hot 0 +#define tiny_math_infinity_y_hot 4 +static unsigned char tiny_math_infinity_bits[] = { + 0x9e, 0x07, 0x61, 0x08, 0x61, 0x08, 0x9e, 0x07, 0x00, 0x00 }; diff --git a/bitmaps/.svn/text-base/tiny_math_integral.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_integral.xbm.svn-base new file mode 100644 index 0000000..1a91ed9 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_integral.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_integral_width 9 +#define tiny_math_integral_height 10 +#define tiny_math_integral_x_hot 0 +#define tiny_math_integral_y_hot 8 +static unsigned char tiny_math_integral_bits[] = { + 0x60, 0x00, 0x90, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x09, 0x00, 0x06, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_math_less.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_less.xbm.svn-base new file mode 100644 index 0000000..9efe921 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_less.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_less_width 6 +#define tiny_math_less_height 7 +#define tiny_math_less_x_hot 0 +#define tiny_math_less_y_hot 6 +static unsigned char tiny_math_less_bits[] = { + 0x18, 0x06, 0x01, 0x06, 0x18, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_math_lessequal.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_lessequal.xbm.svn-base new file mode 100644 index 0000000..ea49a90 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_lessequal.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_lessequal_width 6 +#define tiny_math_lessequal_height 8 +#define tiny_math_lessequal_x_hot 0 +#define tiny_math_lessequal_y_hot 7 +static unsigned char tiny_math_lessequal_bits[] = { + 0x30, 0x0c, 0x02, 0x0c, 0x30, 0x03, 0x0c, 0x30}; diff --git a/bitmaps/.svn/text-base/tiny_math_notequal.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_notequal.xbm.svn-base new file mode 100644 index 0000000..9b71a4f --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_notequal.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_notequal_width 7 +#define tiny_math_notequal_height 8 +#define tiny_math_notequal_x_hot 0 +#define tiny_math_notequal_y_hot 7 +static unsigned char tiny_math_notequal_bits[] = { + 0x08, 0x08, 0x3f, 0x08, 0x04, 0x3f, 0x04, 0x04}; diff --git a/bitmaps/.svn/text-base/tiny_math_numbersign.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_numbersign.xbm.svn-base new file mode 100644 index 0000000..caf5b69 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_numbersign.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_numbersign_width 10 +#define tiny_math_numbersign_height 8 +#define tiny_math_numbersign_x_hot 0 +#define tiny_math_numbersign_y_hot 7 +static unsigned char tiny_math_numbersign_bits[] = { + 0x48, 0x00, 0x48, 0x00, 0xfe, 0x01, 0x48, 0x00, 0x24, 0x00, 0xff, 0x00, + 0x24, 0x00, 0x24, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_math_partialdiff.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_partialdiff.xbm.svn-base new file mode 100644 index 0000000..cf83622 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_partialdiff.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_partialdiff_width 6 +#define tiny_math_partialdiff_height 8 +#define tiny_math_partialdiff_x_hot 0 +#define tiny_math_partialdiff_y_hot 7 +static unsigned char tiny_math_partialdiff_bits[] = { + 0x04, 0x08, 0x08, 0x1e, 0x11, 0x11, 0x11, 0x0e}; diff --git a/bitmaps/.svn/text-base/tiny_math_pi.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_pi.xbm.svn-base new file mode 100644 index 0000000..2d3690d --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_pi.xbm.svn-base @@ -0,0 +1,7 @@ +#define tiny_math_pi_width 9 +#define tiny_math_pi_height 6 +#define tiny_math_pi_x_hot 0 +#define tiny_math_pi_y_hot 5 +static unsigned char tiny_math_pi_bits[] = { + 0xfe, 0x00, 0x25, 0x00, 0x24, 0x00, 0x24, 0x00, 0xa4, 0x00, 0x42, 0x00 + }; diff --git a/bitmaps/.svn/text-base/tiny_math_radical.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_radical.xbm.svn-base new file mode 100644 index 0000000..c281986 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_radical.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_radical_width 8 +#define tiny_math_radical_height 11 +#define tiny_math_radical_x_hot 0 +#define tiny_math_radical_y_hot 8 +static unsigned char tiny_math_radical_bits[] = { + 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x17, 0x14, 0x1c, 0x08, 0x08}; diff --git a/bitmaps/.svn/text-base/tiny_math_summation.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_summation.xbm.svn-base new file mode 100644 index 0000000..d83209f --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_summation.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_summation_width 6 +#define tiny_math_summation_height 9 +#define tiny_math_summation_x_hot 0 +#define tiny_math_summation_y_hot 7 +static unsigned char tiny_math_summation_bits[] = { + 0x1f, 0x11, 0x02, 0x04, 0x08, 0x04, 0x02, 0x11, 0x1f}; diff --git a/bitmaps/.svn/text-base/tiny_math_x.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_x.xbm.svn-base new file mode 100644 index 0000000..e77a564 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_x.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_x_width 8 +#define tiny_math_x_height 6 +#define tiny_math_x_x_hot 0 +#define tiny_math_x_y_hot 5 +static unsigned char tiny_math_x_bits[] = { + 0x26, 0x14, 0x08, 0x14, 0x53, 0x21}; diff --git a/bitmaps/.svn/text-base/tiny_math_y.xbm.svn-base b/bitmaps/.svn/text-base/tiny_math_y.xbm.svn-base new file mode 100644 index 0000000..71c1a76 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_math_y.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_math_y_width 7 +#define tiny_math_y_height 9 +#define tiny_math_y_x_hot 1 +#define tiny_math_y_y_hot 6 +static unsigned char tiny_math_y_bits[] = { + 0x26, 0x24, 0x24, 0x14, 0x18, 0x08, 0x08, 0x05, 0x03}; diff --git a/bitmaps/.svn/text-base/tiny_notdef.xbm.svn-base b/bitmaps/.svn/text-base/tiny_notdef.xbm.svn-base new file mode 100644 index 0000000..57f36b7 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_notdef.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_notdef_width 4 +#define tiny_notdef_height 5 +#define tiny_notdef_x_hot 0 +#define tiny_notdef_y_hot 4 +static unsigned char tiny_notdef_bits[] = { + 0x07, 0x07, 0x07, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_numbersign.xbm.svn-base b/bitmaps/.svn/text-base/tiny_numbersign.xbm.svn-base new file mode 100644 index 0000000..82931c6 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_numbersign.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_numbersign_width 6 +#define tiny_numbersign_height 6 +#define tiny_numbersign_x_hot 0 +#define tiny_numbersign_y_hot 5 +static unsigned char tiny_numbersign_bits[] = { + 0x0a, 0x1f, 0x0a, 0x0a, 0x1f, 0x0a}; diff --git a/bitmaps/.svn/text-base/tiny_one.xbm.svn-base b/bitmaps/.svn/text-base/tiny_one.xbm.svn-base new file mode 100644 index 0000000..050a714 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_one.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_one_width 3 +#define tiny_one_height 7 +#define tiny_one_x_hot 0 +#define tiny_one_y_hot 6 +static unsigned char tiny_one_bits[] = { + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/.svn/text-base/tiny_overscore.xbm.svn-base b/bitmaps/.svn/text-base/tiny_overscore.xbm.svn-base new file mode 100644 index 0000000..c3fb694 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_overscore.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_overscore_width 6 +#define tiny_overscore_height 9 +#define tiny_overscore_x_hot 1 +#define tiny_overscore_y_hot 8 +static unsigned char tiny_overscore_bits[] = { + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_parenleft.xbm.svn-base b/bitmaps/.svn/text-base/tiny_parenleft.xbm.svn-base new file mode 100644 index 0000000..3631fa9 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_parenleft.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_parenleft_width 4 +#define tiny_parenleft_height 9 +#define tiny_parenleft_x_hot 0 +#define tiny_parenleft_y_hot 7 +static unsigned char tiny_parenleft_bits[] = { + 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x04}; diff --git a/bitmaps/.svn/text-base/tiny_parenright.xbm.svn-base b/bitmaps/.svn/text-base/tiny_parenright.xbm.svn-base new file mode 100644 index 0000000..82b182b --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_parenright.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_parenright_width 4 +#define tiny_parenright_height 9 +#define tiny_parenright_x_hot 0 +#define tiny_parenright_y_hot 7 +static unsigned char tiny_parenright_bits[] = { + 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_period.xbm.svn-base b/bitmaps/.svn/text-base/tiny_period.xbm.svn-base new file mode 100644 index 0000000..705a7c8 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_period.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_period_width 3 +#define tiny_period_height 2 +#define tiny_period_x_hot 0 +#define tiny_period_y_hot 1 +static unsigned char tiny_period_bits[] = { + 0x03, 0x03}; diff --git a/bitmaps/.svn/text-base/tiny_quotedbl.xbm.svn-base b/bitmaps/.svn/text-base/tiny_quotedbl.xbm.svn-base new file mode 100644 index 0000000..8ff40d0 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_quotedbl.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_quotedbl_width 4 +#define tiny_quotedbl_height 7 +#define tiny_quotedbl_x_hot 0 +#define tiny_quotedbl_y_hot 6 +static unsigned char tiny_quotedbl_bits[] = { + 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_slash.xbm.svn-base b/bitmaps/.svn/text-base/tiny_slash.xbm.svn-base new file mode 100644 index 0000000..c747f38 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_slash.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_slash_width 4 +#define tiny_slash_height 7 +#define tiny_slash_x_hot 0 +#define tiny_slash_y_hot 6 +static unsigned char tiny_slash_bits[] = { + 0x04, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01}; diff --git a/bitmaps/.svn/text-base/tiny_three.xbm.svn-base b/bitmaps/.svn/text-base/tiny_three.xbm.svn-base new file mode 100644 index 0000000..ba91803 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_three.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_three_width 5 +#define tiny_three_height 7 +#define tiny_three_x_hot 0 +#define tiny_three_y_hot 6 +static unsigned char tiny_three_bits[] = { + 0x06, 0x09, 0x08, 0x06, 0x08, 0x09, 0x06}; diff --git a/bitmaps/.svn/text-base/tiny_two.xbm.svn-base b/bitmaps/.svn/text-base/tiny_two.xbm.svn-base new file mode 100644 index 0000000..af93ea9 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_two.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_two_width 5 +#define tiny_two_height 7 +#define tiny_two_x_hot 0 +#define tiny_two_y_hot 6 +static unsigned char tiny_two_bits[] = { + 0x06, 0x09, 0x08, 0x08, 0x04, 0x02, 0x0f}; diff --git a/bitmaps/.svn/text-base/tiny_twosuperior.xbm.svn-base b/bitmaps/.svn/text-base/tiny_twosuperior.xbm.svn-base new file mode 100644 index 0000000..8761f31 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_twosuperior.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_twosuperior_width 5 +#define tiny_twosuperior_height 9 +#define tiny_twosuperior_x_hot 0 +#define tiny_twosuperior_y_hot 8 +static unsigned char tiny_twosuperior_bits[] = { + 0x02, 0x05, 0x04, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_underscore.xbm.svn-base b/bitmaps/.svn/text-base/tiny_underscore.xbm.svn-base new file mode 100644 index 0000000..b7f3f87 --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_underscore.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_underscore_width 6 +#define tiny_underscore_height 3 +#define tiny_underscore_x_hot 1 +#define tiny_underscore_y_hot 0 +static unsigned char tiny_underscore_bits[] = { + 0x00, 0x00, 0x3f}; diff --git a/bitmaps/.svn/text-base/tiny_xsuperior.xbm.svn-base b/bitmaps/.svn/text-base/tiny_xsuperior.xbm.svn-base new file mode 100644 index 0000000..fbd699f --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_xsuperior.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_xsuperior_width 5 +#define tiny_xsuperior_height 9 +#define tiny_xsuperior_x_hot 0 +#define tiny_xsuperior_y_hot 8 +static unsigned char tiny_xsuperior_bits[] = { + 0x12, 0x0c, 0x04, 0x0a, 0x09, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/.svn/text-base/tiny_zero.xbm.svn-base b/bitmaps/.svn/text-base/tiny_zero.xbm.svn-base new file mode 100644 index 0000000..be374ab --- /dev/null +++ b/bitmaps/.svn/text-base/tiny_zero.xbm.svn-base @@ -0,0 +1,6 @@ +#define tiny_zero_width 5 +#define tiny_zero_height 7 +#define tiny_zero_x_hot 0 +#define tiny_zero_y_hot 6 +static unsigned char tiny_zero_bits[] = { + 0x06, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/bitmaps/CVS/.svn/all-wcprops b/bitmaps/CVS/.svn/all-wcprops new file mode 100644 index 0000000..062cc84 --- /dev/null +++ b/bitmaps/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 36 +/p/x49gp/code/!svn/ver/1/bitmaps/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/bitmaps/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/bitmaps/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/bitmaps/CVS/Entries +END diff --git a/bitmaps/CVS/.svn/entries b/bitmaps/CVS/.svn/entries new file mode 100644 index 0000000..c0b5710 --- /dev/null +++ b/bitmaps/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/bitmaps/CVS +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +Repository +file + + + + +2013-08-23T00:54:47.000000Z +2c17e51e27554afae683fcafbe9562e4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +14 + +Root +file + + + + +2013-08-23T00:54:47.000000Z +f51b768066a9e7d88829b19678326fcd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +60 + +Entries +file + + + + +2013-08-23T00:54:47.000000Z +156818d09a9c64a5b52e9ff57ab0b6f4 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +4370 + diff --git a/bitmaps/CVS/.svn/text-base/Entries.svn-base b/bitmaps/CVS/.svn/text-base/Entries.svn-base new file mode 100644 index 0000000..e32251f --- /dev/null +++ b/bitmaps/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,91 @@ +/ann_alpha.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_battery.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_busy.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_io.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_left.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_right.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_large.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_normal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_round.pix/1.1/Wed Jul 12 11:30:39 2006// +/button_round.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_small.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_tiny.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_A.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_B.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_C.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_D.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_E.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_F.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_G.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_H.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_I.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_J.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_K.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_L.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_M.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_N.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_O.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_P.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Q.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_R.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_S.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_T.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_U.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_V.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_W.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_X.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Y.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Z.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny__i.xbm/1.1/Thu Dec 11 12:19:15 2008// +/tiny_ampersand.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_arrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_arrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_braceleft.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_braceright.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_bracketleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_bracketright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_colon.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_comma.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_equal.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_greater.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_guillemotleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_guillemotright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_hyphen.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_large_comma.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_less.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_arrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_arrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_downarrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_downarrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_e.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_equal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_greater.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_greaterequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_infinity.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_integral.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_less.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_lessequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_notequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_numbersign.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_partialdiff.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_pi.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_radical.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_summation.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_x.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_y.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_notdef.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_numbersign.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_one.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_overscore.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_parenleft.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_parenright.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_period.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_quotedbl.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_slash.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_three.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_two.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_twosuperior.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_underscore.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_xsuperior.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_zero.xbm/1.4/Thu Dec 11 12:14:08 2008// +D diff --git a/bitmaps/CVS/.svn/text-base/Repository.svn-base b/bitmaps/CVS/.svn/text-base/Repository.svn-base new file mode 100644 index 0000000..a01358d --- /dev/null +++ b/bitmaps/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +x49gp/bitmaps diff --git a/bitmaps/CVS/.svn/text-base/Root.svn-base b/bitmaps/CVS/.svn/text-base/Root.svn-base new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/bitmaps/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/bitmaps/CVS/Entries b/bitmaps/CVS/Entries new file mode 100644 index 0000000..e32251f --- /dev/null +++ b/bitmaps/CVS/Entries @@ -0,0 +1,91 @@ +/ann_alpha.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_battery.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_busy.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_io.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_left.xbm/1.4/Thu Dec 11 12:14:08 2008// +/ann_right.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_large.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_normal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_round.pix/1.1/Wed Jul 12 11:30:39 2006// +/button_round.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_small.xbm/1.4/Thu Dec 11 12:14:08 2008// +/button_tiny.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_A.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_B.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_C.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_D.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_E.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_F.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_G.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_H.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_I.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_J.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_K.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_L.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_M.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_N.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_O.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_P.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Q.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_R.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_S.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_T.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_U.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_V.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_W.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_X.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Y.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_Z.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny__i.xbm/1.1/Thu Dec 11 12:19:15 2008// +/tiny_ampersand.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_arrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_arrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_braceleft.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_braceright.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_bracketleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_bracketright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_colon.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_comma.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_equal.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_greater.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_guillemotleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_guillemotright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_hyphen.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_large_comma.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_less.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_arrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_arrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_downarrowleft.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_downarrowright.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_e.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_equal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_greater.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_greaterequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_infinity.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_integral.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_less.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_lessequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_notequal.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_numbersign.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_partialdiff.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_pi.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_radical.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_summation.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_x.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_math_y.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_notdef.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_numbersign.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_one.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_overscore.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_parenleft.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_parenright.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_period.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_quotedbl.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_slash.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_three.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_two.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_twosuperior.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_underscore.xbm/1.5/Thu Dec 11 12:14:08 2008// +/tiny_xsuperior.xbm/1.4/Thu Dec 11 12:14:08 2008// +/tiny_zero.xbm/1.4/Thu Dec 11 12:14:08 2008// +D diff --git a/bitmaps/CVS/Repository b/bitmaps/CVS/Repository new file mode 100644 index 0000000..a01358d --- /dev/null +++ b/bitmaps/CVS/Repository @@ -0,0 +1 @@ +x49gp/bitmaps diff --git a/bitmaps/CVS/Root b/bitmaps/CVS/Root new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/bitmaps/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/bitmaps/ann_alpha.xbm b/bitmaps/ann_alpha.xbm new file mode 100644 index 0000000..e7cfcea --- /dev/null +++ b/bitmaps/ann_alpha.xbm @@ -0,0 +1,5 @@ +#define ann_alpha_width 15 +#define ann_alpha_height 12 +static unsigned char ann_alpha_bits[] = { + 0xe0, 0x03, 0x18, 0x44, 0x0c, 0x4c, 0x06, 0x2c, 0x07, 0x2c, 0x07, 0x1c, + 0x07, 0x0c, 0x07, 0x0c, 0x07, 0x0e, 0x0e, 0x4d, 0xf8, 0x38, 0x00, 0x00}; diff --git a/bitmaps/ann_battery.xbm b/bitmaps/ann_battery.xbm new file mode 100644 index 0000000..b4c6a45 --- /dev/null +++ b/bitmaps/ann_battery.xbm @@ -0,0 +1,5 @@ +#define ann_battery_width 15 +#define ann_battery_height 12 +static unsigned char ann_battery_bits[] = { + 0x04, 0x10, 0x02, 0x20, 0x12, 0x24, 0x09, 0x48, 0xc9, 0x49, 0xc9, 0x49, + 0xc9, 0x49, 0x09, 0x48, 0x12, 0x24, 0x02, 0x20, 0x04, 0x10, 0x00, 0x00}; diff --git a/bitmaps/ann_busy.xbm b/bitmaps/ann_busy.xbm new file mode 100644 index 0000000..1856111 --- /dev/null +++ b/bitmaps/ann_busy.xbm @@ -0,0 +1,5 @@ +#define ann_busy_width 15 +#define ann_busy_height 12 +static unsigned char ann_busy_bits[] = { + 0xfc, 0x1f, 0x08, 0x08, 0x08, 0x08, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, + 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0xc8, 0x09, 0xe8, 0x0b, 0xfc, 0x1f}; diff --git a/bitmaps/ann_io.xbm b/bitmaps/ann_io.xbm new file mode 100644 index 0000000..0c4536d --- /dev/null +++ b/bitmaps/ann_io.xbm @@ -0,0 +1,5 @@ +#define ann_io_width 15 +#define ann_io_height 12 +static unsigned char ann_io_bits[] = { + 0x0c, 0x00, 0x1e, 0x00, 0x33, 0x0c, 0x61, 0x18, 0xcc, 0x30, 0xfe, 0x7f, + 0xfe, 0x7f, 0xcc, 0x30, 0x61, 0x18, 0x33, 0x0c, 0x1e, 0x00, 0x0c, 0x00}; diff --git a/bitmaps/ann_left.xbm b/bitmaps/ann_left.xbm new file mode 100644 index 0000000..604b9d5 --- /dev/null +++ b/bitmaps/ann_left.xbm @@ -0,0 +1,5 @@ +#define ann_left_width 15 +#define ann_left_height 12 +static unsigned char ann_left_bits[] = { + 0xfe, 0x3f, 0xff, 0x7f, 0x9f, 0x7f, 0xcf, 0x7f, 0xe7, 0x7f, 0x03, 0x78, + 0x03, 0x70, 0xe7, 0x73, 0xcf, 0x73, 0x9f, 0x73, 0xff, 0x73, 0xfe, 0x33}; diff --git a/bitmaps/ann_right.xbm b/bitmaps/ann_right.xbm new file mode 100644 index 0000000..bd9bd6f --- /dev/null +++ b/bitmaps/ann_right.xbm @@ -0,0 +1,5 @@ +#define ann_right_width 15 +#define ann_right_height 12 +static unsigned char ann_right_bits[] = { + 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7c, 0xff, 0x79, 0xff, 0x73, 0x0f, 0x60, + 0x07, 0x60, 0xe7, 0x73, 0xe7, 0x79, 0xe7, 0x7c, 0xe7, 0x7f, 0xe6, 0x3f}; diff --git a/bitmaps/button_large.xbm b/bitmaps/button_large.xbm new file mode 100644 index 0000000..11570f8 --- /dev/null +++ b/bitmaps/button_large.xbm @@ -0,0 +1,19 @@ +#define button_large_width 46 +#define button_large_height 32 +static unsigned char button_large_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/button_normal.xbm b/bitmaps/button_normal.xbm new file mode 100644 index 0000000..e979828 --- /dev/null +++ b/bitmaps/button_normal.xbm @@ -0,0 +1,17 @@ +#define button_normal_width 46 +#define button_normal_height 28 +static unsigned char button_normal_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/button_round.pix b/bitmaps/button_round.pix new file mode 100644 index 0000000..e25abb9 --- /dev/null +++ b/bitmaps/button_round.pix @@ -0,0 +1,157 @@ +/* GdkPixbuf RGBA C-Source image dump */ + +#ifdef __SUNPRO_C +#pragma align 4 (button_round) +#endif +#ifdef __GNUC__ +static const guint8 button_round[] __attribute__ ((__aligned__ (4))) = +#else +static const guint8 button_round[] = +#endif +{ "" + /* Pixbuf magic (0x47646b50) */ + "GdkP" + /* length: header (24) + pixel_data (4356) */ + "\0\0\21\34" + /* pixdata_type (0x1010002) */ + "\1\1\0\2" + /* rowstride (132) */ + "\0\0\0\204" + /* width (33) */ + "\0\0\0!" + /* height (33) */ + "\0\0\0!" + /* pixel_data: */ + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\255\0\0\0\244\0\0\0\232\0\0\0\232" + "\0\0\0\232\0\0\0\244\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\247\0\0\0\215\0\0\0|\0\0\0o\0\0\0_\0\0\0Z\0\0\0Z\0\0" + "\0_\0\0\0f\0\0\0o\0\0\0\201\0\0\0\225\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0" + "\0\211\0\0\0h\0\0\0W\0\0\0D\0\0\0:\0\0\0""1\0\0\0/\0\0\0,\0\0\0/\0\0" + "\0""4\0\0\0:\0\0\0H\0\0\0Z\0\0\0r\0\0\0\215\0\0\0\255\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0o\0\0\0R\0\0\0:\0" + "\0\0*\0\0\0!\0\0\0\34\0\0\0\27\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\27\0" + "\0\0\35\0\0\0#\0\0\0/\0\0\0A\0\0\0W\0\0\0|\0\0\0\244\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\261\0\0\0\215\0\0\0_\0\0\0D\0\0\0,\0\0\0\35\0\0\0" + "\26\0\0\0\21\0\0\0\16\0\0\0\15\0\0\0\13\0\0\0\13\0\0\0\13\0\0\0\15\0" + "\0\0\16\0\0\0\22\0\0\0\27\0\0\0\37\0\0\0""1\0\0\0K\0\0\0h\0\0\0\225\0" + "\0\0\273\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\211\0\0\0_\0\0\0:\0\0\0#\0\0\0\27\0\0\0\20" + "\0\0\0\14\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\6\0\0\0\6\0" + "\0\0\7\0\0\0\11\0\0\0\15\0\0\0\22\0\0\0\31\0\0\0(\0\0\0D\0\0\0h\0\0\0" + "\225\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\222\0\0\0_\0\0\0:\0\0\0!\0\0\0\24\0\0\0\15\0\0\0\11\0" + "\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0" + "\4\0\0\0\5\0\0\0\6\0\0\0\11\0\0\0\17\0\0\0\27\0\0\0&\0\0\0D\0\0\0o\0" + "\0\0\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\244\0\0\0o\0\0\0A\0\0\0#\0\0\0\24\0\0\0\15\0\0\0\10\0\0\0\5\0\0\0" + "\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0" + "\0\0\3\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0\16\0\0\0\27\0\0\0*\0\0\0K\0\0\0" + "|\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\211" + "\0\0\0O\0\0\0*\0\0\0\27\0\0\0\15\0\0\0\10\0\0\0\5\0\0\0\4\0\0\0\3\0\0" + "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2" + "\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\10\0\0\0\17\0\0\0\32\0\0\0""1\0\0\0_\0" + "\0\0\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\244\0\0\0f\0\0" + "\0:\0\0\0\35\0\0\0\20\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0" + "\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0" + "\0\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\12\0\0\0\22\0\0\0!\0\0\0A\0\0\0" + "r\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\211\0\0\0R\0\0\0(\0" + "\0\0\24\0\0\0\13\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2" + "\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\7\0\0\0\15\0\0\0\31\0\0\0""1\0\0\0_\0" + "\0\0\225\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0y\0\0\0A\0\0\0\37\0\0\0" + "\20\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\2\0\0\0\3\0\0\0\5\0\0\0\12\0\0\0\23\0\0\0&\0\0\0O\0\0\0\211" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0f\0\0\0""4\0\0\0\31\0\0\0\15" + "\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\10\0\0\0\17\0\0\0\37\0\0\0A\0\0\0y\0\0" + "\0\261\0\0\0\0\0\0\0\0\0\0\0\232\0\0\0_\0\0\0/\0\0\0\27\0\0\0\14\0\0" + "\0\6\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\32\0\0\0""7\0\0\0h\0\0\0" + "\255\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0W\0\0\0*\0\0\0\24\0\0\0\12\0\0\0" + "\5\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\2\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0f\0\0\0\244" + "\0\0\0\0\0\0\0\0\0\0\0\222\0\0\0R\0\0\0(\0\0\0\23\0\0\0\11\0\0\0\5\0" + "\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0" + "\0\0\2\0\0\0\4\0\0\0\6\0\0\0\14\0\0\0\27\0\0\0""1\0\0\0_\0\0\0\244\0" + "\0\0\0\0\0\0\0\0\0\0\225\0\0\0W\0\0\0*\0\0\0\24\0\0\0\12\0\0\0\5\0\0" + "\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" + "\0\2\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0f\0\0\0\244\0\0" + "\0\0\0\0\0\0\0\0\0\232\0\0\0_\0\0\0/\0\0\0\26\0\0\0\13\0\0\0\6\0\0\0" + "\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0" + "\3\0\0\0\4\0\0\0\6\0\0\0\15\0\0\0\32\0\0\0""7\0\0\0h\0\0\0\255\0\0\0" + "\0\0\0\0\0\0\0\0\244\0\0\0f\0\0\0""4\0\0\0\31\0\0\0\15\0\0\0\6\0\0\0" + "\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0" + "\3\0\0\0\4\0\0\0\10\0\0\0\17\0\0\0\37\0\0\0A\0\0\0r\0\0\0\261\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0y\0\0\0A\0\0\0\37\0\0\0\20\0\0\0\10\0\0\0\5\0\0" + "\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0" + "\0\5\0\0\0\12\0\0\0\23\0\0\0&\0\0\0O\0\0\0\211\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\211\0\0\0R\0\0\0(\0\0\0\24\0\0\0\13\0\0\0\6\0\0\0\4" + "\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\7" + "\0\0\0\15\0\0\0\27\0\0\0""1\0\0\0_\0\0\0\225\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\244\0\0\0f\0\0\0""7\0\0\0\35\0\0\0\20\0\0\0\10\0\0\0\5" + "\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0" + "\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\12" + "\0\0\0\23\0\0\0!\0\0\0D\0\0\0r\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\211\0\0\0O\0\0\0*\0\0\0\27\0\0\0\15\0\0\0\10\0\0\0" + "\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0" + "\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\10\0\0\0\17\0\0" + "\0\32\0\0\0""1\0\0\0_\0\0\0\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\244\0\0\0o\0\0\0D\0\0\0#\0\0\0\24\0\0\0\15\0\0\0\7\0" + "\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0" + "\2\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0\16\0\0\0\27\0\0\0*" + "\0\0\0K\0\0\0|\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\222\0\0\0_\0\0\0:\0\0\0!\0\0\0\24\0\0\0\15\0\0\0\11" + "\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0" + "\0\4\0\0\0\5\0\0\0\6\0\0\0\12\0\0\0\17\0\0\0\27\0\0\0&\0\0\0D\0\0\0h" + "\0\0\0\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\215\0\0\0_\0\0\0>\0\0\0#\0\0\0\27\0\0\0\20\0\0\0" + "\14\0\0\0\11\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\6\0\0\0\6\0\0\0\7" + "\0\0\0\11\0\0\0\15\0\0\0\22\0\0\0\32\0\0\0*\0\0\0D\0\0\0h\0\0\0\225\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\261\0\0\0\215\0\0\0_\0\0\0D\0\0\0*\0\0\0\35\0\0\0\26" + "\0\0\0\21\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\12\0\0\0\13\0\0\0\15\0\0\0" + "\17\0\0\0\22\0\0\0\27\0\0\0\37\0\0\0""1\0\0\0K\0\0\0o\0\0\0\225\0\0\0" + "\273\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\225\0\0\0r\0\0\0R\0\0\0:\0\0\0" + "*\0\0\0\37\0\0\0\32\0\0\0\27\0\0\0\26\0\0\0\26\0\0\0\27\0\0\0\31\0\0" + "\0\35\0\0\0#\0\0\0/\0\0\0A\0\0\0Z\0\0\0y\0\0\0\244\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0\211\0\0\0h\0\0\0R" + "\0\0\0D\0\0\0:\0\0\0""1\0\0\0/\0\0\0,\0\0\0/\0\0\0""4\0\0\0:\0\0\0H\0" + "\0\0Z\0\0\0r\0\0\0\215\0\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\247\0\0\0\215\0\0\0|\0" + "\0\0o\0\0\0f\0\0\0_\0\0\0_\0\0\0_\0\0\0f\0\0\0o\0\0\0\201\0\0\0\225\0" + "\0\0\255\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\255\0" + "\0\0\244\0\0\0\232\0\0\0\232\0\0\0\232\0\0\0\244\0\0\0\255\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0"}; + + diff --git a/bitmaps/button_round.xbm b/bitmaps/button_round.xbm new file mode 100644 index 0000000..f0d3292 --- /dev/null +++ b/bitmaps/button_round.xbm @@ -0,0 +1,17 @@ +#define button_round_width 33 +#define button_round_height 33 +static unsigned char button_round_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0xfc, + 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x80, 0xff, 0xff, 0x03, + 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0xf0, + 0xff, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, + 0x3f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, + 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, + 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xfe, + 0xff, 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, + 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, + 0xf8, 0xff, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00, 0xe0, 0xff, + 0xff, 0x0f, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x80, 0xff, 0xff, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, + 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/button_small.xbm b/bitmaps/button_small.xbm new file mode 100644 index 0000000..e3508d3 --- /dev/null +++ b/bitmaps/button_small.xbm @@ -0,0 +1,15 @@ +#define button_small_width 36 +#define button_small_height 28 +static unsigned char button_small_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0xff, + 0x03, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, + 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfc, 0xff, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/button_tiny.xbm b/bitmaps/button_tiny.xbm new file mode 100644 index 0000000..39d0abb --- /dev/null +++ b/bitmaps/button_tiny.xbm @@ -0,0 +1,13 @@ +#define button_tiny_width 36 +#define button_tiny_height 22 +static unsigned char button_tiny_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0xff, 0x03, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, + 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, + 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, + 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, + 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0xff, 0x07, 0xfc, + 0xff, 0xff, 0xff, 0x03, 0xf8, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00}; diff --git a/bitmaps/tiny_A.xbm b/bitmaps/tiny_A.xbm new file mode 100644 index 0000000..cd0e0d2 --- /dev/null +++ b/bitmaps/tiny_A.xbm @@ -0,0 +1,6 @@ +#define tiny_A_width 5 +#define tiny_A_height 7 +#define tiny_A_x_hot 0 +#define tiny_A_y_hot 6 +static unsigned char tiny_A_bits[] = { + 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09}; diff --git a/bitmaps/tiny_B.xbm b/bitmaps/tiny_B.xbm new file mode 100644 index 0000000..3fa73c1 --- /dev/null +++ b/bitmaps/tiny_B.xbm @@ -0,0 +1,6 @@ +#define tiny_B_width 5 +#define tiny_B_height 7 +#define tiny_B_x_hot 0 +#define tiny_B_y_hot 6 +static unsigned char tiny_B_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07}; diff --git a/bitmaps/tiny_C.xbm b/bitmaps/tiny_C.xbm new file mode 100644 index 0000000..bd10b3e --- /dev/null +++ b/bitmaps/tiny_C.xbm @@ -0,0 +1,6 @@ +#define tiny_C_width 5 +#define tiny_C_height 7 +#define tiny_C_x_hot 0 +#define tiny_C_y_hot 6 +static unsigned char tiny_C_bits[] = { + 0x06, 0x09, 0x01, 0x01, 0x01, 0x09, 0x06}; diff --git a/bitmaps/tiny_D.xbm b/bitmaps/tiny_D.xbm new file mode 100644 index 0000000..4c49bf8 --- /dev/null +++ b/bitmaps/tiny_D.xbm @@ -0,0 +1,6 @@ +#define tiny_D_width 5 +#define tiny_D_height 7 +#define tiny_D_x_hot 0 +#define tiny_D_y_hot 6 +static unsigned char tiny_D_bits[] = { + 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07}; diff --git a/bitmaps/tiny_E.xbm b/bitmaps/tiny_E.xbm new file mode 100644 index 0000000..ee69976 --- /dev/null +++ b/bitmaps/tiny_E.xbm @@ -0,0 +1,6 @@ +#define tiny_E_width 4 +#define tiny_E_height 7 +#define tiny_E_x_hot 0 +#define tiny_E_y_hot 6 +static unsigned char tiny_E_bits[] = { + 0x17, 0x01, 0x01, 0x03, 0x01, 0x01, 0x17}; diff --git a/bitmaps/tiny_F.xbm b/bitmaps/tiny_F.xbm new file mode 100644 index 0000000..1a998e7 --- /dev/null +++ b/bitmaps/tiny_F.xbm @@ -0,0 +1,6 @@ +#define tiny_F_width 4 +#define tiny_F_height 7 +#define tiny_F_x_hot 0 +#define tiny_F_y_hot 6 +static unsigned char tiny_F_bits[] = { + 0x07, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01}; diff --git a/bitmaps/tiny_G.xbm b/bitmaps/tiny_G.xbm new file mode 100644 index 0000000..e0e0814 --- /dev/null +++ b/bitmaps/tiny_G.xbm @@ -0,0 +1,6 @@ +#define tiny_G_width 6 +#define tiny_G_height 7 +#define tiny_G_x_hot 0 +#define tiny_G_y_hot 6 +static unsigned char tiny_G_bits[] = { + 0x0e, 0x11, 0x01, 0x01, 0x19, 0x11, 0x0e}; diff --git a/bitmaps/tiny_H.xbm b/bitmaps/tiny_H.xbm new file mode 100644 index 0000000..2efb290 --- /dev/null +++ b/bitmaps/tiny_H.xbm @@ -0,0 +1,6 @@ +#define tiny_H_width 5 +#define tiny_H_height 7 +#define tiny_H_x_hot 0 +#define tiny_H_y_hot 6 +static unsigned char tiny_H_bits[] = { + 0x09, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09}; diff --git a/bitmaps/tiny_I.xbm b/bitmaps/tiny_I.xbm new file mode 100644 index 0000000..7c85dee --- /dev/null +++ b/bitmaps/tiny_I.xbm @@ -0,0 +1,6 @@ +#define tiny_I_width 4 +#define tiny_I_height 7 +#define tiny_I_x_hot 0 +#define tiny_I_y_hot 6 +static unsigned char tiny_I_bits[] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/tiny_J.xbm b/bitmaps/tiny_J.xbm new file mode 100644 index 0000000..ab7de19 --- /dev/null +++ b/bitmaps/tiny_J.xbm @@ -0,0 +1,6 @@ +#define tiny_J_width 5 +#define tiny_J_height 7 +#define tiny_J_x_hot 0 +#define tiny_J_y_hot 6 +static unsigned char tiny_J_bits[] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06}; diff --git a/bitmaps/tiny_K.xbm b/bitmaps/tiny_K.xbm new file mode 100644 index 0000000..f9563c4 --- /dev/null +++ b/bitmaps/tiny_K.xbm @@ -0,0 +1,6 @@ +#define tiny_K_width 5 +#define tiny_K_height 7 +#define tiny_K_x_hot 0 +#define tiny_K_y_hot 6 +static unsigned char tiny_K_bits[] = { + 0x09, 0x05, 0x05, 0x03, 0x05, 0x05, 0x09}; diff --git a/bitmaps/tiny_L.xbm b/bitmaps/tiny_L.xbm new file mode 100644 index 0000000..946b6f2 --- /dev/null +++ b/bitmaps/tiny_L.xbm @@ -0,0 +1,6 @@ +#define tiny_L_width 4 +#define tiny_L_height 7 +#define tiny_L_x_hot 0 +#define tiny_L_y_hot 6 +static unsigned char tiny_L_bits[] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07}; diff --git a/bitmaps/tiny_M.xbm b/bitmaps/tiny_M.xbm new file mode 100644 index 0000000..4091719 --- /dev/null +++ b/bitmaps/tiny_M.xbm @@ -0,0 +1,6 @@ +#define tiny_M_width 6 +#define tiny_M_height 7 +#define tiny_M_x_hot 0 +#define tiny_M_y_hot 6 +static unsigned char tiny_M_bits[] = { + 0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11}; diff --git a/bitmaps/tiny_N.xbm b/bitmaps/tiny_N.xbm new file mode 100644 index 0000000..068d682 --- /dev/null +++ b/bitmaps/tiny_N.xbm @@ -0,0 +1,6 @@ +#define tiny_N_width 5 +#define tiny_N_height 7 +#define tiny_N_x_hot 0 +#define tiny_N_y_hot 6 +static unsigned char tiny_N_bits[] = { + 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x09}; diff --git a/bitmaps/tiny_O.xbm b/bitmaps/tiny_O.xbm new file mode 100644 index 0000000..4ef2d53 --- /dev/null +++ b/bitmaps/tiny_O.xbm @@ -0,0 +1,6 @@ +#define tiny_O_width 5 +#define tiny_O_height 7 +#define tiny_O_x_hot 0 +#define tiny_O_y_hot 6 +static unsigned char tiny_O_bits[] = { + 0x06, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/bitmaps/tiny_P.xbm b/bitmaps/tiny_P.xbm new file mode 100644 index 0000000..7fd19eb --- /dev/null +++ b/bitmaps/tiny_P.xbm @@ -0,0 +1,6 @@ +#define tiny_P_width 5 +#define tiny_P_height 7 +#define tiny_P_x_hot 0 +#define tiny_P_y_hot 6 +static unsigned char tiny_P_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x01}; diff --git a/bitmaps/tiny_Q.xbm b/bitmaps/tiny_Q.xbm new file mode 100644 index 0000000..4ecebc5 --- /dev/null +++ b/bitmaps/tiny_Q.xbm @@ -0,0 +1,6 @@ +#define tiny_Q_width 6 +#define tiny_Q_height 7 +#define tiny_Q_x_hot 0 +#define tiny_Q_y_hot 6 +static unsigned char tiny_Q_bits[] = { + 0x0e, 0x11, 0x11, 0x11, 0x15, 0x09, 0x16}; diff --git a/bitmaps/tiny_R.xbm b/bitmaps/tiny_R.xbm new file mode 100644 index 0000000..5088b22 --- /dev/null +++ b/bitmaps/tiny_R.xbm @@ -0,0 +1,6 @@ +#define tiny_R_width 5 +#define tiny_R_height 7 +#define tiny_R_x_hot 0 +#define tiny_R_y_hot 6 +static unsigned char tiny_R_bits[] = { + 0x07, 0x09, 0x09, 0x07, 0x05, 0x09, 0x09}; diff --git a/bitmaps/tiny_S.xbm b/bitmaps/tiny_S.xbm new file mode 100644 index 0000000..d567911 --- /dev/null +++ b/bitmaps/tiny_S.xbm @@ -0,0 +1,6 @@ +#define tiny_S_width 5 +#define tiny_S_height 7 +#define tiny_S_x_hot 0 +#define tiny_S_y_hot 6 +static unsigned char tiny_S_bits[] = { + 0x06, 0x09, 0x01, 0x06, 0x08, 0x09, 0x06}; diff --git a/bitmaps/tiny_T.xbm b/bitmaps/tiny_T.xbm new file mode 100644 index 0000000..4cb3ea4 --- /dev/null +++ b/bitmaps/tiny_T.xbm @@ -0,0 +1,6 @@ +#define tiny_T_width 5 +#define tiny_T_height 7 +#define tiny_T_x_hot 1 +#define tiny_T_y_hot 6 +static unsigned char tiny_T_bits[] = { + 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}; diff --git a/bitmaps/tiny_U.xbm b/bitmaps/tiny_U.xbm new file mode 100644 index 0000000..f9df60e --- /dev/null +++ b/bitmaps/tiny_U.xbm @@ -0,0 +1,6 @@ +#define tiny_U_width 5 +#define tiny_U_height 7 +#define tiny_U_x_hot 0 +#define tiny_U_y_hot 6 +static unsigned char tiny_U_bits[] = { + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/bitmaps/tiny_V.xbm b/bitmaps/tiny_V.xbm new file mode 100644 index 0000000..07bc1cc --- /dev/null +++ b/bitmaps/tiny_V.xbm @@ -0,0 +1,6 @@ +#define tiny_V_width 5 +#define tiny_V_height 7 +#define tiny_V_x_hot 0 +#define tiny_V_y_hot 6 +static unsigned char tiny_V_bits[] = { + 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06}; diff --git a/bitmaps/tiny_W.xbm b/bitmaps/tiny_W.xbm new file mode 100644 index 0000000..c8a878e --- /dev/null +++ b/bitmaps/tiny_W.xbm @@ -0,0 +1,6 @@ +#define tiny_W_width 6 +#define tiny_W_height 7 +#define tiny_W_x_hot 0 +#define tiny_W_y_hot 6 +static unsigned char tiny_W_bits[] = { + 0x11, 0x11, 0x11, 0x15, 0x15, 0x1b, 0x11}; diff --git a/bitmaps/tiny_X.xbm b/bitmaps/tiny_X.xbm new file mode 100644 index 0000000..82b3429 --- /dev/null +++ b/bitmaps/tiny_X.xbm @@ -0,0 +1,6 @@ +#define tiny_X_width 5 +#define tiny_X_height 7 +#define tiny_X_x_hot 0 +#define tiny_X_y_hot 6 +static unsigned char tiny_X_bits[] = { + 0x09, 0x09, 0x06, 0x06, 0x06, 0x09, 0x09}; diff --git a/bitmaps/tiny_Y.xbm b/bitmaps/tiny_Y.xbm new file mode 100644 index 0000000..1b51bf6 --- /dev/null +++ b/bitmaps/tiny_Y.xbm @@ -0,0 +1,6 @@ +#define tiny_Y_width 6 +#define tiny_Y_height 7 +#define tiny_Y_x_hot 0 +#define tiny_Y_y_hot 6 +static unsigned char tiny_Y_bits[] = { + 0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04}; diff --git a/bitmaps/tiny_Z.xbm b/bitmaps/tiny_Z.xbm new file mode 100644 index 0000000..f20296b --- /dev/null +++ b/bitmaps/tiny_Z.xbm @@ -0,0 +1,6 @@ +#define tiny_Z_width 5 +#define tiny_Z_height 7 +#define tiny_Z_x_hot 0 +#define tiny_Z_y_hot 6 +static unsigned char tiny_Z_bits[] = { + 0x0f, 0x08, 0x04, 0x04, 0x02, 0x01, 0x0f}; diff --git a/bitmaps/tiny__i.xbm b/bitmaps/tiny__i.xbm new file mode 100644 index 0000000..4706d51 --- /dev/null +++ b/bitmaps/tiny__i.xbm @@ -0,0 +1,6 @@ +#define tiny_i_width 4 +#define tiny_i_height 7 +#define tiny_i_x_hot 0 +#define tiny_i_y_hot 6 +static unsigned char tiny_i_bits[] = { + 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/tiny_ampersand.xbm b/bitmaps/tiny_ampersand.xbm new file mode 100644 index 0000000..86f807b --- /dev/null +++ b/bitmaps/tiny_ampersand.xbm @@ -0,0 +1,6 @@ +#define tiny_ampersand_width 6 +#define tiny_ampersand_height 7 +#define tiny_ampersand_x_hot 0 +#define tiny_ampersand_y_hot 6 +static unsigned char tiny_ampersand_bits[] = { + 0x06, 0x09, 0x06, 0x16, 0x09, 0x09, 0x16}; diff --git a/bitmaps/tiny_arrowleft.xbm b/bitmaps/tiny_arrowleft.xbm new file mode 100644 index 0000000..25a8126 --- /dev/null +++ b/bitmaps/tiny_arrowleft.xbm @@ -0,0 +1,6 @@ +#define tiny_arrowleft_width 7 +#define tiny_arrowleft_height 5 +#define tiny_arrowleft_x_hot 0 +#define tiny_arrowleft_y_hot 4 +static unsigned char tiny_arrowleft_bits[] = { + 0x02, 0x3f, 0x02, 0x00, 0x00 }; diff --git a/bitmaps/tiny_arrowright.xbm b/bitmaps/tiny_arrowright.xbm new file mode 100644 index 0000000..ab37763 --- /dev/null +++ b/bitmaps/tiny_arrowright.xbm @@ -0,0 +1,6 @@ +#define tiny_arrowright_width 7 +#define tiny_arrowright_height 5 +#define tiny_arrowright_x_hot 0 +#define tiny_arrowright_y_hot 4 +static unsigned char tiny_arrowright_bits[] = { + 0x10, 0x3f, 0x10, 0x00, 0x00 }; diff --git a/bitmaps/tiny_braceleft.xbm b/bitmaps/tiny_braceleft.xbm new file mode 100644 index 0000000..0f6ba86 --- /dev/null +++ b/bitmaps/tiny_braceleft.xbm @@ -0,0 +1,6 @@ +#define tiny_braceleft_width 4 +#define tiny_braceleft_height 9 +#define tiny_braceleft_x_hot 0 +#define tiny_braceleft_y_hot 7 +static unsigned char tiny_braceleft_bits[] = { + 0x04, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x04}; diff --git a/bitmaps/tiny_braceright.xbm b/bitmaps/tiny_braceright.xbm new file mode 100644 index 0000000..2af45ee --- /dev/null +++ b/bitmaps/tiny_braceright.xbm @@ -0,0 +1,6 @@ +#define tiny_braceright_width 4 +#define tiny_braceright_height 9 +#define tiny_braceright_x_hot 0 +#define tiny_braceright_y_hot 7 +static unsigned char tiny_braceright_bits[] = { + 0x01, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01}; diff --git a/bitmaps/tiny_bracketleft.xbm b/bitmaps/tiny_bracketleft.xbm new file mode 100644 index 0000000..f3ae7ea --- /dev/null +++ b/bitmaps/tiny_bracketleft.xbm @@ -0,0 +1,6 @@ +#define tiny_bracketleft_width 4 +#define tiny_bracketleft_height 9 +#define tiny_bracketleft_x_hot 0 +#define tiny_bracketleft_y_hot 7 +static unsigned char tiny_bracketleft_bits[] = { + 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07}; diff --git a/bitmaps/tiny_bracketright.xbm b/bitmaps/tiny_bracketright.xbm new file mode 100644 index 0000000..de4d785 --- /dev/null +++ b/bitmaps/tiny_bracketright.xbm @@ -0,0 +1,6 @@ +#define tiny_bracketright_width 4 +#define tiny_bracketright_height 9 +#define tiny_bracketright_x_hot 0 +#define tiny_bracketright_y_hot 7 +static unsigned char tiny_bracketright_bits[] = { + 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07}; diff --git a/bitmaps/tiny_colon.xbm b/bitmaps/tiny_colon.xbm new file mode 100644 index 0000000..0dc2622 --- /dev/null +++ b/bitmaps/tiny_colon.xbm @@ -0,0 +1,6 @@ +#define tiny_colon_width 3 +#define tiny_colon_height 6 +#define tiny_colon_x_hot 0 +#define tiny_colon_y_hot 5 +static unsigned char tiny_colon_bits[] = { + 0x03, 0x03, 0x00, 0x00, 0x03, 0x03 }; diff --git a/bitmaps/tiny_comma.xbm b/bitmaps/tiny_comma.xbm new file mode 100644 index 0000000..2adbc03 --- /dev/null +++ b/bitmaps/tiny_comma.xbm @@ -0,0 +1,6 @@ +#define tiny_comma_width 4 +#define tiny_comma_height 3 +#define tiny_comma_x_hot 0 +#define tiny_comma_y_hot 1 +static unsigned char tiny_comma_bits[] = { + 0x06, 0x06, 0x03}; diff --git a/bitmaps/tiny_equal.xbm b/bitmaps/tiny_equal.xbm new file mode 100644 index 0000000..512b5c8 --- /dev/null +++ b/bitmaps/tiny_equal.xbm @@ -0,0 +1,6 @@ +#define tiny_equal_width 5 +#define tiny_equal_height 5 +#define tiny_equal_x_hot 0 +#define tiny_equal_y_hot 4 +static unsigned char tiny_equal_bits[] = { + 0x0f, 0x00, 0x0f, 0x00, 0x00}; diff --git a/bitmaps/tiny_greater.xbm b/bitmaps/tiny_greater.xbm new file mode 100644 index 0000000..44d9caf --- /dev/null +++ b/bitmaps/tiny_greater.xbm @@ -0,0 +1,6 @@ +#define tiny_greater_width 5 +#define tiny_greater_height 7 +#define tiny_greater_x_hot 0 +#define tiny_greater_y_hot 6 +static unsigned char tiny_greater_bits[] = { + 0x01, 0x02, 0x04, 0x08, 0x04, 0x02, 0x01}; diff --git a/bitmaps/tiny_guillemotleft.xbm b/bitmaps/tiny_guillemotleft.xbm new file mode 100644 index 0000000..96fc88a --- /dev/null +++ b/bitmaps/tiny_guillemotleft.xbm @@ -0,0 +1,6 @@ +#define tiny_guillemotleft_width 11 +#define tiny_guillemotleft_height 6 +#define tiny_guillemotleft_x_hot 0 +#define tiny_guillemotleft_y_hot 5 +static unsigned char tiny_guillemotleft_bits[] = { + 0x18, 0x03, 0xc6, 0x00, 0x21, 0x00, 0xc6, 0x00, 0x18, 0x03, 0x00, 0x00}; diff --git a/bitmaps/tiny_guillemotright.xbm b/bitmaps/tiny_guillemotright.xbm new file mode 100644 index 0000000..50d736e --- /dev/null +++ b/bitmaps/tiny_guillemotright.xbm @@ -0,0 +1,6 @@ +#define tiny_guillemotright_width 11 +#define tiny_guillemotright_height 6 +#define tiny_guillemotright_x_hot 0 +#define tiny_guillemotright_y_hot 5 +static unsigned char tiny_guillemotright_bits[] = { + 0x63, 0x00, 0x8c, 0x01, 0x10, 0x02, 0x8c, 0x01, 0x63, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_hyphen.xbm b/bitmaps/tiny_hyphen.xbm new file mode 100644 index 0000000..4696e05 --- /dev/null +++ b/bitmaps/tiny_hyphen.xbm @@ -0,0 +1,6 @@ +#define tiny_hyphen_width 5 +#define tiny_hyphen_height 4 +#define tiny_hyphen_x_hot 0 +#define tiny_hyphen_y_hot 3 +static unsigned char tiny_hyphen_bits[] = { + 0x0f, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_large_comma.xbm b/bitmaps/tiny_large_comma.xbm new file mode 100644 index 0000000..f130f02 --- /dev/null +++ b/bitmaps/tiny_large_comma.xbm @@ -0,0 +1,6 @@ +#define tiny_large_comma_width 4 +#define tiny_large_comma_height 6 +#define tiny_large_comma_x_hot 0 +#define tiny_large_comma_y_hot 2 +static unsigned char tiny_large_comma_bits[] = { + 0x07, 0x07, 0x07, 0x04, 0x02, 0x01 }; diff --git a/bitmaps/tiny_less.xbm b/bitmaps/tiny_less.xbm new file mode 100644 index 0000000..c9ee854 --- /dev/null +++ b/bitmaps/tiny_less.xbm @@ -0,0 +1,6 @@ +#define tiny_less_width 5 +#define tiny_less_height 7 +#define tiny_less_x_hot 0 +#define tiny_less_y_hot 6 +static unsigned char tiny_less_bits[] = { + 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08}; diff --git a/bitmaps/tiny_math_arrowleft.xbm b/bitmaps/tiny_math_arrowleft.xbm new file mode 100644 index 0000000..117ee37 --- /dev/null +++ b/bitmaps/tiny_math_arrowleft.xbm @@ -0,0 +1,7 @@ +#define tiny_math_arrowleft_width 12 +#define tiny_math_arrowleft_height 6 +#define tiny_math_arrowleft_x_hot 0 +#define tiny_math_arrowleft_y_hot 5 +static unsigned char tiny_math_arrowleft_bits[] = { + 0x10, 0x00, 0x1c, 0x00, 0xff, 0x07, 0x1c, 0x00, 0x10, 0x00, 0x00, 0x00 + }; diff --git a/bitmaps/tiny_math_arrowright.xbm b/bitmaps/tiny_math_arrowright.xbm new file mode 100644 index 0000000..5f23875 --- /dev/null +++ b/bitmaps/tiny_math_arrowright.xbm @@ -0,0 +1,7 @@ +#define tiny_math_arrowright_width 12 +#define tiny_math_arrowright_height 6 +#define tiny_math_arrowright_x_hot 0 +#define tiny_math_arrowright_y_hot 5 +static unsigned char tiny_math_arrowright_bits[] = { + 0x40, 0x00, 0xc0, 0x01, 0xff, 0x07, 0xc0, 0x01, 0x40, 0x00, 0x00, 0x00 + }; diff --git a/bitmaps/tiny_math_downarrowleft.xbm b/bitmaps/tiny_math_downarrowleft.xbm new file mode 100644 index 0000000..103f777 --- /dev/null +++ b/bitmaps/tiny_math_downarrowleft.xbm @@ -0,0 +1,7 @@ +#define tiny_math_downarrowleft_width 12 +#define tiny_math_downarrowleft_height 8 +#define tiny_math_downarrowleft_x_hot 0 +#define tiny_math_downarrowleft_y_hot 7 +static unsigned char tiny_math_downarrowleft_bits[] = { + 0x00, 0x04, 0x00, 0x04, 0x10, 0x04, 0x1c, 0x04, 0xff, 0x07, 0x1c, 0x00, + 0x10, 0x00, 0x00, 0x00 }; diff --git a/bitmaps/tiny_math_downarrowright.xbm b/bitmaps/tiny_math_downarrowright.xbm new file mode 100644 index 0000000..bf7c8bc --- /dev/null +++ b/bitmaps/tiny_math_downarrowright.xbm @@ -0,0 +1,7 @@ +#define tiny_math_downarrowright_width 12 +#define tiny_math_downarrowright_height 8 +#define tiny_math_downarrowright_x_hot 0 +#define tiny_math_downarrowright_y_hot 7 +static unsigned char tiny_math_downarrowright_bits[] = { + 0x01, 0x00, 0x01, 0x00, 0x41, 0x00, 0xc1, 0x01, 0xff, 0x07, 0xc0, 0x01, + 0x40, 0x00, 0x00, 0x00 }; diff --git a/bitmaps/tiny_math_e.xbm b/bitmaps/tiny_math_e.xbm new file mode 100644 index 0000000..1cb6fa3 --- /dev/null +++ b/bitmaps/tiny_math_e.xbm @@ -0,0 +1,6 @@ +#define tiny_math_e_width 6 +#define tiny_math_e_height 6 +#define tiny_math_e_x_hot 0 +#define tiny_math_e_y_hot 5 +static unsigned char tiny_math_e_bits[] = { + 0x0c, 0x12, 0x09, 0x07, 0x11, 0x0e}; diff --git a/bitmaps/tiny_math_equal.xbm b/bitmaps/tiny_math_equal.xbm new file mode 100644 index 0000000..cf30759 --- /dev/null +++ b/bitmaps/tiny_math_equal.xbm @@ -0,0 +1,6 @@ +#define tiny_math_equal_width 7 +#define tiny_math_equal_height 6 +#define tiny_math_equal_x_hot 0 +#define tiny_math_equal_y_hot 5 +static unsigned char tiny_math_equal_bits[] = { + 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00}; diff --git a/bitmaps/tiny_math_greater.xbm b/bitmaps/tiny_math_greater.xbm new file mode 100644 index 0000000..581b902 --- /dev/null +++ b/bitmaps/tiny_math_greater.xbm @@ -0,0 +1,6 @@ +#define tiny_math_greater_width 6 +#define tiny_math_greater_height 7 +#define tiny_math_greater_x_hot 0 +#define tiny_math_greater_y_hot 6 +static unsigned char tiny_math_greater_bits[] = { + 0x03, 0x0c, 0x10, 0x0c, 0x03, 0x00, 0x00}; diff --git a/bitmaps/tiny_math_greaterequal.xbm b/bitmaps/tiny_math_greaterequal.xbm new file mode 100644 index 0000000..7675bf9 --- /dev/null +++ b/bitmaps/tiny_math_greaterequal.xbm @@ -0,0 +1,6 @@ +#define tiny_math_greaterequal_width 6 +#define tiny_math_greaterequal_height 8 +#define tiny_math_greaterequal_x_hot 0 +#define tiny_math_greaterequal_y_hot 7 +static unsigned char tiny_math_greaterequal_bits[] = { + 0x03, 0x0c, 0x10, 0x0c, 0x03, 0x30, 0x0c, 0x03}; diff --git a/bitmaps/tiny_math_infinity.xbm b/bitmaps/tiny_math_infinity.xbm new file mode 100644 index 0000000..ed48a6e --- /dev/null +++ b/bitmaps/tiny_math_infinity.xbm @@ -0,0 +1,6 @@ +#define tiny_math_infinity_width 13 +#define tiny_math_infinity_height 5 +#define tiny_math_infinity_x_hot 0 +#define tiny_math_infinity_y_hot 4 +static unsigned char tiny_math_infinity_bits[] = { + 0x9e, 0x07, 0x61, 0x08, 0x61, 0x08, 0x9e, 0x07, 0x00, 0x00 }; diff --git a/bitmaps/tiny_math_integral.xbm b/bitmaps/tiny_math_integral.xbm new file mode 100644 index 0000000..1a91ed9 --- /dev/null +++ b/bitmaps/tiny_math_integral.xbm @@ -0,0 +1,7 @@ +#define tiny_math_integral_width 9 +#define tiny_math_integral_height 10 +#define tiny_math_integral_x_hot 0 +#define tiny_math_integral_y_hot 8 +static unsigned char tiny_math_integral_bits[] = { + 0x60, 0x00, 0x90, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x09, 0x00, 0x06, 0x00}; diff --git a/bitmaps/tiny_math_less.xbm b/bitmaps/tiny_math_less.xbm new file mode 100644 index 0000000..9efe921 --- /dev/null +++ b/bitmaps/tiny_math_less.xbm @@ -0,0 +1,6 @@ +#define tiny_math_less_width 6 +#define tiny_math_less_height 7 +#define tiny_math_less_x_hot 0 +#define tiny_math_less_y_hot 6 +static unsigned char tiny_math_less_bits[] = { + 0x18, 0x06, 0x01, 0x06, 0x18, 0x00, 0x00}; diff --git a/bitmaps/tiny_math_lessequal.xbm b/bitmaps/tiny_math_lessequal.xbm new file mode 100644 index 0000000..ea49a90 --- /dev/null +++ b/bitmaps/tiny_math_lessequal.xbm @@ -0,0 +1,6 @@ +#define tiny_math_lessequal_width 6 +#define tiny_math_lessequal_height 8 +#define tiny_math_lessequal_x_hot 0 +#define tiny_math_lessequal_y_hot 7 +static unsigned char tiny_math_lessequal_bits[] = { + 0x30, 0x0c, 0x02, 0x0c, 0x30, 0x03, 0x0c, 0x30}; diff --git a/bitmaps/tiny_math_notequal.xbm b/bitmaps/tiny_math_notequal.xbm new file mode 100644 index 0000000..9b71a4f --- /dev/null +++ b/bitmaps/tiny_math_notequal.xbm @@ -0,0 +1,6 @@ +#define tiny_math_notequal_width 7 +#define tiny_math_notequal_height 8 +#define tiny_math_notequal_x_hot 0 +#define tiny_math_notequal_y_hot 7 +static unsigned char tiny_math_notequal_bits[] = { + 0x08, 0x08, 0x3f, 0x08, 0x04, 0x3f, 0x04, 0x04}; diff --git a/bitmaps/tiny_math_numbersign.xbm b/bitmaps/tiny_math_numbersign.xbm new file mode 100644 index 0000000..caf5b69 --- /dev/null +++ b/bitmaps/tiny_math_numbersign.xbm @@ -0,0 +1,7 @@ +#define tiny_math_numbersign_width 10 +#define tiny_math_numbersign_height 8 +#define tiny_math_numbersign_x_hot 0 +#define tiny_math_numbersign_y_hot 7 +static unsigned char tiny_math_numbersign_bits[] = { + 0x48, 0x00, 0x48, 0x00, 0xfe, 0x01, 0x48, 0x00, 0x24, 0x00, 0xff, 0x00, + 0x24, 0x00, 0x24, 0x00}; diff --git a/bitmaps/tiny_math_partialdiff.xbm b/bitmaps/tiny_math_partialdiff.xbm new file mode 100644 index 0000000..cf83622 --- /dev/null +++ b/bitmaps/tiny_math_partialdiff.xbm @@ -0,0 +1,6 @@ +#define tiny_math_partialdiff_width 6 +#define tiny_math_partialdiff_height 8 +#define tiny_math_partialdiff_x_hot 0 +#define tiny_math_partialdiff_y_hot 7 +static unsigned char tiny_math_partialdiff_bits[] = { + 0x04, 0x08, 0x08, 0x1e, 0x11, 0x11, 0x11, 0x0e}; diff --git a/bitmaps/tiny_math_pi.xbm b/bitmaps/tiny_math_pi.xbm new file mode 100644 index 0000000..2d3690d --- /dev/null +++ b/bitmaps/tiny_math_pi.xbm @@ -0,0 +1,7 @@ +#define tiny_math_pi_width 9 +#define tiny_math_pi_height 6 +#define tiny_math_pi_x_hot 0 +#define tiny_math_pi_y_hot 5 +static unsigned char tiny_math_pi_bits[] = { + 0xfe, 0x00, 0x25, 0x00, 0x24, 0x00, 0x24, 0x00, 0xa4, 0x00, 0x42, 0x00 + }; diff --git a/bitmaps/tiny_math_radical.xbm b/bitmaps/tiny_math_radical.xbm new file mode 100644 index 0000000..c281986 --- /dev/null +++ b/bitmaps/tiny_math_radical.xbm @@ -0,0 +1,6 @@ +#define tiny_math_radical_width 8 +#define tiny_math_radical_height 11 +#define tiny_math_radical_x_hot 0 +#define tiny_math_radical_y_hot 8 +static unsigned char tiny_math_radical_bits[] = { + 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x17, 0x14, 0x1c, 0x08, 0x08}; diff --git a/bitmaps/tiny_math_summation.xbm b/bitmaps/tiny_math_summation.xbm new file mode 100644 index 0000000..d83209f --- /dev/null +++ b/bitmaps/tiny_math_summation.xbm @@ -0,0 +1,6 @@ +#define tiny_math_summation_width 6 +#define tiny_math_summation_height 9 +#define tiny_math_summation_x_hot 0 +#define tiny_math_summation_y_hot 7 +static unsigned char tiny_math_summation_bits[] = { + 0x1f, 0x11, 0x02, 0x04, 0x08, 0x04, 0x02, 0x11, 0x1f}; diff --git a/bitmaps/tiny_math_x.xbm b/bitmaps/tiny_math_x.xbm new file mode 100644 index 0000000..e77a564 --- /dev/null +++ b/bitmaps/tiny_math_x.xbm @@ -0,0 +1,6 @@ +#define tiny_math_x_width 8 +#define tiny_math_x_height 6 +#define tiny_math_x_x_hot 0 +#define tiny_math_x_y_hot 5 +static unsigned char tiny_math_x_bits[] = { + 0x26, 0x14, 0x08, 0x14, 0x53, 0x21}; diff --git a/bitmaps/tiny_math_y.xbm b/bitmaps/tiny_math_y.xbm new file mode 100644 index 0000000..71c1a76 --- /dev/null +++ b/bitmaps/tiny_math_y.xbm @@ -0,0 +1,6 @@ +#define tiny_math_y_width 7 +#define tiny_math_y_height 9 +#define tiny_math_y_x_hot 1 +#define tiny_math_y_y_hot 6 +static unsigned char tiny_math_y_bits[] = { + 0x26, 0x24, 0x24, 0x14, 0x18, 0x08, 0x08, 0x05, 0x03}; diff --git a/bitmaps/tiny_notdef.xbm b/bitmaps/tiny_notdef.xbm new file mode 100644 index 0000000..57f36b7 --- /dev/null +++ b/bitmaps/tiny_notdef.xbm @@ -0,0 +1,6 @@ +#define tiny_notdef_width 4 +#define tiny_notdef_height 5 +#define tiny_notdef_x_hot 0 +#define tiny_notdef_y_hot 4 +static unsigned char tiny_notdef_bits[] = { + 0x07, 0x07, 0x07, 0x00, 0x00}; diff --git a/bitmaps/tiny_numbersign.xbm b/bitmaps/tiny_numbersign.xbm new file mode 100644 index 0000000..82931c6 --- /dev/null +++ b/bitmaps/tiny_numbersign.xbm @@ -0,0 +1,6 @@ +#define tiny_numbersign_width 6 +#define tiny_numbersign_height 6 +#define tiny_numbersign_x_hot 0 +#define tiny_numbersign_y_hot 5 +static unsigned char tiny_numbersign_bits[] = { + 0x0a, 0x1f, 0x0a, 0x0a, 0x1f, 0x0a}; diff --git a/bitmaps/tiny_one.xbm b/bitmaps/tiny_one.xbm new file mode 100644 index 0000000..050a714 --- /dev/null +++ b/bitmaps/tiny_one.xbm @@ -0,0 +1,6 @@ +#define tiny_one_width 3 +#define tiny_one_height 7 +#define tiny_one_x_hot 0 +#define tiny_one_y_hot 6 +static unsigned char tiny_one_bits[] = { + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; diff --git a/bitmaps/tiny_overscore.xbm b/bitmaps/tiny_overscore.xbm new file mode 100644 index 0000000..c3fb694 --- /dev/null +++ b/bitmaps/tiny_overscore.xbm @@ -0,0 +1,6 @@ +#define tiny_overscore_width 6 +#define tiny_overscore_height 9 +#define tiny_overscore_x_hot 1 +#define tiny_overscore_y_hot 8 +static unsigned char tiny_overscore_bits[] = { + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_parenleft.xbm b/bitmaps/tiny_parenleft.xbm new file mode 100644 index 0000000..3631fa9 --- /dev/null +++ b/bitmaps/tiny_parenleft.xbm @@ -0,0 +1,6 @@ +#define tiny_parenleft_width 4 +#define tiny_parenleft_height 9 +#define tiny_parenleft_x_hot 0 +#define tiny_parenleft_y_hot 7 +static unsigned char tiny_parenleft_bits[] = { + 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x02, 0x04}; diff --git a/bitmaps/tiny_parenright.xbm b/bitmaps/tiny_parenright.xbm new file mode 100644 index 0000000..82b182b --- /dev/null +++ b/bitmaps/tiny_parenright.xbm @@ -0,0 +1,6 @@ +#define tiny_parenright_width 4 +#define tiny_parenright_height 9 +#define tiny_parenright_x_hot 0 +#define tiny_parenright_y_hot 7 +static unsigned char tiny_parenright_bits[] = { + 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01}; diff --git a/bitmaps/tiny_period.xbm b/bitmaps/tiny_period.xbm new file mode 100644 index 0000000..705a7c8 --- /dev/null +++ b/bitmaps/tiny_period.xbm @@ -0,0 +1,6 @@ +#define tiny_period_width 3 +#define tiny_period_height 2 +#define tiny_period_x_hot 0 +#define tiny_period_y_hot 1 +static unsigned char tiny_period_bits[] = { + 0x03, 0x03}; diff --git a/bitmaps/tiny_quotedbl.xbm b/bitmaps/tiny_quotedbl.xbm new file mode 100644 index 0000000..8ff40d0 --- /dev/null +++ b/bitmaps/tiny_quotedbl.xbm @@ -0,0 +1,6 @@ +#define tiny_quotedbl_width 4 +#define tiny_quotedbl_height 7 +#define tiny_quotedbl_x_hot 0 +#define tiny_quotedbl_y_hot 6 +static unsigned char tiny_quotedbl_bits[] = { + 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_slash.xbm b/bitmaps/tiny_slash.xbm new file mode 100644 index 0000000..c747f38 --- /dev/null +++ b/bitmaps/tiny_slash.xbm @@ -0,0 +1,6 @@ +#define tiny_slash_width 4 +#define tiny_slash_height 7 +#define tiny_slash_x_hot 0 +#define tiny_slash_y_hot 6 +static unsigned char tiny_slash_bits[] = { + 0x04, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01}; diff --git a/bitmaps/tiny_three.xbm b/bitmaps/tiny_three.xbm new file mode 100644 index 0000000..ba91803 --- /dev/null +++ b/bitmaps/tiny_three.xbm @@ -0,0 +1,6 @@ +#define tiny_three_width 5 +#define tiny_three_height 7 +#define tiny_three_x_hot 0 +#define tiny_three_y_hot 6 +static unsigned char tiny_three_bits[] = { + 0x06, 0x09, 0x08, 0x06, 0x08, 0x09, 0x06}; diff --git a/bitmaps/tiny_two.xbm b/bitmaps/tiny_two.xbm new file mode 100644 index 0000000..af93ea9 --- /dev/null +++ b/bitmaps/tiny_two.xbm @@ -0,0 +1,6 @@ +#define tiny_two_width 5 +#define tiny_two_height 7 +#define tiny_two_x_hot 0 +#define tiny_two_y_hot 6 +static unsigned char tiny_two_bits[] = { + 0x06, 0x09, 0x08, 0x08, 0x04, 0x02, 0x0f}; diff --git a/bitmaps/tiny_twosuperior.xbm b/bitmaps/tiny_twosuperior.xbm new file mode 100644 index 0000000..8761f31 --- /dev/null +++ b/bitmaps/tiny_twosuperior.xbm @@ -0,0 +1,6 @@ +#define tiny_twosuperior_width 5 +#define tiny_twosuperior_height 9 +#define tiny_twosuperior_x_hot 0 +#define tiny_twosuperior_y_hot 8 +static unsigned char tiny_twosuperior_bits[] = { + 0x02, 0x05, 0x04, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_underscore.xbm b/bitmaps/tiny_underscore.xbm new file mode 100644 index 0000000..b7f3f87 --- /dev/null +++ b/bitmaps/tiny_underscore.xbm @@ -0,0 +1,6 @@ +#define tiny_underscore_width 6 +#define tiny_underscore_height 3 +#define tiny_underscore_x_hot 1 +#define tiny_underscore_y_hot 0 +static unsigned char tiny_underscore_bits[] = { + 0x00, 0x00, 0x3f}; diff --git a/bitmaps/tiny_xsuperior.xbm b/bitmaps/tiny_xsuperior.xbm new file mode 100644 index 0000000..fbd699f --- /dev/null +++ b/bitmaps/tiny_xsuperior.xbm @@ -0,0 +1,6 @@ +#define tiny_xsuperior_width 5 +#define tiny_xsuperior_height 9 +#define tiny_xsuperior_x_hot 0 +#define tiny_xsuperior_y_hot 8 +static unsigned char tiny_xsuperior_bits[] = { + 0x12, 0x0c, 0x04, 0x0a, 0x09, 0x00, 0x00, 0x00, 0x00}; diff --git a/bitmaps/tiny_zero.xbm b/bitmaps/tiny_zero.xbm new file mode 100644 index 0000000..be374ab --- /dev/null +++ b/bitmaps/tiny_zero.xbm @@ -0,0 +1,6 @@ +#define tiny_zero_width 5 +#define tiny_zero_height 7 +#define tiny_zero_x_hot 0 +#define tiny_zero_y_hot 6 +static unsigned char tiny_zero_bits[] = { + 0x06, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06}; diff --git a/block-qcow.c b/block-qcow.c new file mode 100644 index 0000000..86425aa --- /dev/null +++ b/block-qcow.c @@ -0,0 +1,600 @@ +/* + * Block driver for the QCOW format + * + * Copyright (c) 2004-2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifdef QEMU_OLD +#include "vl.h" +#else +#include "qemu-common.h" +#include "block.h" +#endif +#include "block_int.h" +#include +#if 0 +#include "aes.h" +#endif + +/**************************************************************/ +/* QEMU COW block driver with compression and encryption support */ + +#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) +#define QCOW_VERSION 1 + +#define QCOW_CRYPT_NONE 0 +#define QCOW_CRYPT_AES 1 + +#define QCOW_OFLAG_COMPRESSED (1LL << 63) + +typedef struct QCowHeader { + uint32_t magic; + uint32_t version; + uint64_t backing_file_offset; + uint32_t backing_file_size; + uint32_t mtime; + uint64_t size; /* in bytes */ + uint8_t cluster_bits; + uint8_t l2_bits; + uint32_t crypt_method; + uint64_t l1_table_offset; +} QCowHeader; + +#define L2_CACHE_SIZE 16 + +typedef struct BDRVQcowState { + BlockDriverState *hd; + int cluster_bits; + int cluster_size; + int cluster_sectors; + int l2_bits; + int l2_size; + int l1_size; + uint64_t cluster_offset_mask; + uint64_t l1_table_offset; + uint64_t *l1_table; + uint64_t *l2_cache; + uint64_t l2_cache_offsets[L2_CACHE_SIZE]; + uint32_t l2_cache_counts[L2_CACHE_SIZE]; + uint8_t *cluster_cache; + uint8_t *cluster_data; + uint64_t cluster_cache_offset; +} BDRVQcowState; + +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); + +static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + const QCowHeader *cow_header = (const void *)buf; + + if (buf_size >= sizeof(QCowHeader) && + be32_to_cpu(cow_header->magic) == QCOW_MAGIC && + be32_to_cpu(cow_header->version) == QCOW_VERSION) + return 100; + else + return 0; +} + +static int qcow_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVQcowState *s = bs->opaque; + int len, i, shift, ret; + QCowHeader header; + + ret = bdrv_file_open(&s->hd, filename, flags); + if (ret < 0) + return ret; + if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) + goto fail; + be32_to_cpus(&header.magic); + be32_to_cpus(&header.version); + be64_to_cpus(&header.backing_file_offset); + be32_to_cpus(&header.backing_file_size); + be32_to_cpus(&header.mtime); + be64_to_cpus(&header.size); + be32_to_cpus(&header.crypt_method); + be64_to_cpus(&header.l1_table_offset); + + if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) + goto fail; + if (header.size <= 1 || header.cluster_bits < 9) + goto fail; + if (header.crypt_method > QCOW_CRYPT_AES) + goto fail; + s->cluster_bits = header.cluster_bits; + s->cluster_size = 1 << s->cluster_bits; + s->cluster_sectors = 1 << (s->cluster_bits - 9); + s->l2_bits = header.l2_bits; + s->l2_size = 1 << s->l2_bits; + bs->total_sectors = header.size / 512; + s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1; + + /* read the level 1 table */ + shift = s->cluster_bits + s->l2_bits; + s->l1_size = (header.size + (1LL << shift) - 1) >> shift; + + s->l1_table_offset = header.l1_table_offset; + s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); + if (!s->l1_table) + goto fail; + if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != + s->l1_size * sizeof(uint64_t)) + goto fail; + for(i = 0;i < s->l1_size; i++) { + be64_to_cpus(&s->l1_table[i]); + } + /* alloc L2 cache */ + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); + if (!s->l2_cache) + goto fail; + s->cluster_cache = qemu_malloc(s->cluster_size); + if (!s->cluster_cache) + goto fail; + s->cluster_data = qemu_malloc(s->cluster_size); + if (!s->cluster_data) + goto fail; + s->cluster_cache_offset = -1; + + /* read the backing file name */ + if (header.backing_file_offset != 0) { + len = header.backing_file_size; + if (len > 1023) + len = 1023; + if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len) + goto fail; + bs->backing_file[len] = '\0'; + } + return 0; + + fail: + qemu_free(s->l1_table); + qemu_free(s->l2_cache); + qemu_free(s->cluster_cache); + qemu_free(s->cluster_data); + bdrv_delete(s->hd); + return -1; +} + +/* 'allocate' is: + * + * 0 to not allocate. + * + * 1 to allocate a normal cluster (for sector indexes 'n_start' to + * 'n_end') + * + * 2 to allocate a compressed cluster of size + * 'compressed_size'. 'compressed_size' must be > 0 and < + * cluster_size + * + * return 0 if not allocated. + */ +static uint64_t get_cluster_offset(BlockDriverState *bs, + uint64_t offset, int allocate, + int compressed_size, + int n_start, int n_end) +{ + BDRVQcowState *s = bs->opaque; + int min_index, i, j, l1_index, l2_index; + uint64_t l2_offset, *l2_table, cluster_offset, tmp; + uint32_t min_count; + int new_l2_table; + + l1_index = offset >> (s->l2_bits + s->cluster_bits); + l2_offset = s->l1_table[l1_index]; + new_l2_table = 0; + if (!l2_offset) { + if (!allocate) + return 0; + /* allocate a new l2 entry */ + l2_offset = bdrv_getlength(s->hd); + /* round to cluster size */ + l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); + /* update the L1 entry */ + s->l1_table[l1_index] = l2_offset; + tmp = cpu_to_be64(l2_offset); + if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), + &tmp, sizeof(tmp)) != sizeof(tmp)) + return 0; + new_l2_table = 1; + } + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (l2_offset == s->l2_cache_offsets[i]) { + /* increment the hit count */ + if (++s->l2_cache_counts[i] == 0xffffffff) { + for(j = 0; j < L2_CACHE_SIZE; j++) { + s->l2_cache_counts[j] >>= 1; + } + } + l2_table = s->l2_cache + (i << s->l2_bits); + goto found; + } + } + /* not found: load a new entry in the least used one */ + min_index = 0; + min_count = 0xffffffff; + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (s->l2_cache_counts[i] < min_count) { + min_count = s->l2_cache_counts[i]; + min_index = i; + } + } + l2_table = s->l2_cache + (min_index << s->l2_bits); + if (new_l2_table) { + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); + if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return 0; + } else { + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return 0; + } + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + found: + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + cluster_offset = be64_to_cpu(l2_table[l2_index]); + if (!cluster_offset || + ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) { + if (!allocate) + return 0; + /* allocate a new cluster */ + if ((cluster_offset & QCOW_OFLAG_COMPRESSED) && + (n_end - n_start) < s->cluster_sectors) { + /* if the cluster is already compressed, we must + decompress it in the case it is not completely + overwritten */ + if (decompress_cluster(s, cluster_offset) < 0) + return 0; + cluster_offset = bdrv_getlength(s->hd); + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + /* write the cluster content */ + if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) != + s->cluster_size) + return -1; + } else { + cluster_offset = bdrv_getlength(s->hd); + if (allocate == 1) { + /* round to cluster size */ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + bdrv_truncate(s->hd, cluster_offset + s->cluster_size); + } else { + cluster_offset |= QCOW_OFLAG_COMPRESSED | + (uint64_t)compressed_size << (63 - s->cluster_bits); + } + } + /* update L2 table */ + tmp = cpu_to_be64(cluster_offset); + l2_table[l2_index] = tmp; + if (bdrv_pwrite(s->hd, + l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) + return 0; + } + return cluster_offset; +} + +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum) +{ + BDRVQcowState *s = bs->opaque; + int index_in_cluster, n; + uint64_t cluster_offset; + + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + *pnum = n; + return (cluster_offset != 0); +} + +static int decompress_buffer(uint8_t *out_buf, int out_buf_size, + const uint8_t *buf, int buf_size) +{ + z_stream strm1, *strm = &strm1; + int ret, out_len; + + memset(strm, 0, sizeof(*strm)); + + strm->next_in = (uint8_t *)buf; + strm->avail_in = buf_size; + strm->next_out = out_buf; + strm->avail_out = out_buf_size; + + ret = inflateInit2(strm, -12); + if (ret != Z_OK) + return -1; + ret = inflate(strm, Z_FINISH); + out_len = strm->next_out - out_buf; + if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || + out_len != out_buf_size) { + inflateEnd(strm); + return -1; + } + inflateEnd(strm); + return 0; +} + +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) +{ + int ret, csize; + uint64_t coffset; + + coffset = cluster_offset & s->cluster_offset_mask; + if (s->cluster_cache_offset != coffset) { + csize = cluster_offset >> (63 - s->cluster_bits); + csize &= (s->cluster_size - 1); + ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize); + if (ret != csize) + return -1; + if (decompress_buffer(s->cluster_cache, s->cluster_size, + s->cluster_data, csize) < 0) { + return -1; + } + s->cluster_cache_offset = coffset; + } + return 0; +} + +static int qcow_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + int ret, index_in_cluster, n; + uint64_t cluster_offset; + + while (nb_sectors > 0) { + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + if (!cluster_offset) { + if (bs->backing_hd) { + /* read from the base image */ + ret = bdrv_read(bs->backing_hd, sector_num, buf, n); + if (ret < 0) + return -1; + } else { + memset(buf, 0, 512 * n); + } + } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + if (decompress_cluster(s, cluster_offset) < 0) + return -1; + memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); + } else { + ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + if (ret != n * 512) + return -1; + } + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + return 0; +} + +static int qcow_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + int ret, index_in_cluster, n; + uint64_t cluster_offset; + + while (nb_sectors > 0) { + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, + index_in_cluster, + index_in_cluster + n); + if (!cluster_offset) + return -1; + { + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + } + if (ret != n * 512) + return -1; + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + s->cluster_cache_offset = -1; /* disable compressed cache */ + return 0; +} + +static void qcow_close(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + qemu_free(s->l1_table); + qemu_free(s->l2_cache); + qemu_free(s->cluster_cache); + qemu_free(s->cluster_data); + bdrv_delete(s->hd); +} + +static int qcow_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd, header_size, backing_filename_len, l1_size, i, shift; + QCowHeader header; + uint64_t tmp; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); + if (fd < 0) + return -1; + memset(&header, 0, sizeof(header)); + header.magic = cpu_to_be32(QCOW_MAGIC); + header.version = cpu_to_be32(QCOW_VERSION); + header.size = cpu_to_be64(total_size * 512); + header_size = sizeof(header); + backing_filename_len = 0; + if (backing_file) { + header.backing_file_offset = cpu_to_be64(header_size); + backing_filename_len = strlen(backing_file); + header.backing_file_size = cpu_to_be32(backing_filename_len); + header_size += backing_filename_len; + header.mtime = cpu_to_be32(0); + header.cluster_bits = 9; /* 512 byte cluster to avoid copying + unmodifyed sectors */ + header.l2_bits = 12; /* 32 KB L2 tables */ + } else { + header.cluster_bits = 12; /* 4 KB clusters */ + header.l2_bits = 9; /* 4 KB L2 tables */ + } + header_size = (header_size + 7) & ~7; + shift = header.cluster_bits + header.l2_bits; + l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift; + + header.l1_table_offset = cpu_to_be64(header_size); + if (flags) { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); + } else { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); + } + + /* write all the data */ + write(fd, &header, sizeof(header)); + if (backing_file) { + write(fd, backing_file, backing_filename_len); + } + lseek(fd, header_size, SEEK_SET); + tmp = 0; + for(i = 0;i < l1_size; i++) { + write(fd, &tmp, sizeof(tmp)); + } + close(fd); + return 0; +} + +static int qcow_make_empty(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + uint32_t l1_length = s->l1_size * sizeof(uint64_t); + int ret; + + memset(s->l1_table, 0, l1_length); + if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0) + return -1; + ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); + if (ret < 0) + return ret; + + memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); + memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t)); + memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t)); + + return 0; +} + +/* XXX: put compressed sectors first, then all the cluster aligned + tables to avoid losing bytes in alignment */ +static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + z_stream strm; + int ret, out_len; + uint8_t *out_buf; + uint64_t cluster_offset; + + if (nb_sectors != s->cluster_sectors) + return -EINVAL; + + out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128); + if (!out_buf) + return -1; + + /* best compression, small window, no zlib header */ + memset(&strm, 0, sizeof(strm)); + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, + Z_DEFLATED, -12, + 9, Z_DEFAULT_STRATEGY); + if (ret != 0) { + qemu_free(out_buf); + return -1; + } + + strm.avail_in = s->cluster_size; + strm.next_in = (uint8_t *)buf; + strm.avail_out = s->cluster_size; + strm.next_out = out_buf; + + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END && ret != Z_OK) { + qemu_free(out_buf); + deflateEnd(&strm); + return -1; + } + out_len = strm.next_out - out_buf; + + deflateEnd(&strm); + + if (ret != Z_STREAM_END || out_len >= s->cluster_size) { + /* could not compress: write normal cluster */ + qcow_write(bs, sector_num, buf, s->cluster_sectors); + } else { + cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, + out_len, 0, 0); + cluster_offset &= s->cluster_offset_mask; + if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { + qemu_free(out_buf); + return -1; + } + } + + qemu_free(out_buf); + return 0; +} + +static void qcow_flush(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + bdrv_flush(s->hd); +} + +static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + BDRVQcowState *s = bs->opaque; + bdi->cluster_size = s->cluster_size; + return 0; +} + +BlockDriver bdrv_qcow = { + "qcow", + sizeof(BDRVQcowState), + qcow_probe, + qcow_open, + qcow_read, + qcow_write, + qcow_close, + qcow_create, + qcow_flush, + qcow_is_allocated, + NULL, + qcow_make_empty, + + .bdrv_write_compressed = qcow_write_compressed, + .bdrv_get_info = qcow_get_info, +}; diff --git a/block-raw.c b/block-raw.c new file mode 100644 index 0000000..294a680 --- /dev/null +++ b/block-raw.c @@ -0,0 +1,885 @@ +/* + * Block driver for RAW files + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifdef QEMU_OLD +#include "vl.h" +#else +#include "qemu-common.h" +#include "block.h" +#endif +#include "block_int.h" +#include +#ifndef _WIN32 + +#ifdef X49GP +#define QEMU_TOOL +#endif + +#ifdef CONFIG_COCOA +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#endif + +#ifdef __sun__ +#define _POSIX_PTHREAD_SEMANTICS 1 +#include +#include +#endif +#ifdef __linux__ +#include +#include +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + +//#define DEBUG_FLOPPY + +#define FTYPE_FILE 0 +#define FTYPE_CD 1 +#define FTYPE_FD 2 + +/* if the FD is not accessed during that time (in ms), we try to + reopen it to see if the disk has been changed */ +#define FD_OPEN_TIMEOUT 1000 + +typedef struct BDRVRawState { + int fd; + int type; +#if defined(__linux__) + /* linux floppy specific */ + int fd_open_flags; + int64_t fd_open_time; + int64_t fd_error_time; + int fd_got_error; + int fd_media_changed; +#endif +} BDRVRawState; + +static int fd_open(BlockDriverState *bs); + +static int raw_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + int fd, open_flags, ret; + + open_flags = O_BINARY; + if ((flags & BDRV_O_ACCESS) == O_RDWR) { + open_flags |= O_RDWR; + } else { + open_flags |= O_RDONLY; + bs->read_only = 1; + } + if (flags & BDRV_O_CREAT) + open_flags |= O_CREAT | O_TRUNC; + + s->type = FTYPE_FILE; + + fd = open(filename, open_flags, 0644); + if (fd < 0) { + ret = -errno; + if (ret == -EROFS) + ret = -EACCES; + return ret; + } + s->fd = fd; + return 0; +} + +/* XXX: use host sector size if necessary with: +#ifdef DIOCGSECTORSIZE + { + unsigned int sectorsize = 512; + if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && + sectorsize > bufsize) + bufsize = sectorsize; + } +#endif +#ifdef CONFIG_COCOA + u_int32_t blockSize = 512; + if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { + bufsize = blockSize; + } +#endif +*/ + +static int raw_pread(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + int ret; + + ret = fd_open(bs); + if (ret < 0) + return ret; + + lseek(s->fd, offset, SEEK_SET); + ret = read(s->fd, buf, count); + return ret; +} + +static int raw_pwrite(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + int ret; + + ret = fd_open(bs); + if (ret < 0) + return ret; + + lseek(s->fd, offset, SEEK_SET); + ret = write(s->fd, buf, count); + return ret; +} + +static void raw_close(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + if (s->fd >= 0) { + close(s->fd); + s->fd = -1; + } +} + +static int raw_truncate(BlockDriverState *bs, int64_t offset) +{ + BDRVRawState *s = bs->opaque; + if (s->type != FTYPE_FILE) + return -ENOTSUP; + if (ftruncate(s->fd, offset) < 0) + return -errno; + return 0; +} + +static int64_t raw_getlength(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + int fd = s->fd; + int64_t size; +#ifdef _BSD + struct stat sb; +#endif +#ifdef __sun__ + struct dk_minfo minfo; + int rv; +#endif + int ret; + + ret = fd_open(bs); + if (ret < 0) + return ret; + +#ifdef _BSD + if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { +#ifdef DIOCGMEDIASIZE + if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) +#endif +#ifdef CONFIG_COCOA + size = LONG_LONG_MAX; +#else + size = lseek(fd, 0LL, SEEK_END); +#endif + } else +#endif +#ifdef __sun__ + /* + * use the DKIOCGMEDIAINFO ioctl to read the size. + */ + rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo ); + if ( rv != -1 ) { + size = minfo.dki_lbsize * minfo.dki_capacity; + } else /* there are reports that lseek on some devices + fails, but irc discussion said that contingency + on contingency was overkill */ +#endif + { + size = lseek(fd, 0, SEEK_END); + } + return size; +} + +static int raw_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd; + + if (flags || backing_file) + return -ENOTSUP; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + 0644); + if (fd < 0) + return -EIO; + ftruncate(fd, total_size * 512); + close(fd); + return 0; +} + +static void raw_flush(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + fsync(s->fd); +} + +BlockDriver bdrv_raw = { + "raw", + sizeof(BDRVRawState), + NULL, /* no probe for protocols */ + raw_open, + NULL, + NULL, + raw_close, + raw_create, + raw_flush, + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_truncate = raw_truncate, + .bdrv_getlength = raw_getlength, +}; + +/***********************************************/ +/* host device */ + +#ifdef CONFIG_COCOA +static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); +static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); + +kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) +{ + kern_return_t kernResult; + mach_port_t masterPort; + CFMutableDictionaryRef classesToMatch; + + kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); + if ( KERN_SUCCESS != kernResult ) { + printf( "IOMasterPort returned %d\n", kernResult ); + } + + classesToMatch = IOServiceMatching( kIOCDMediaClass ); + if ( classesToMatch == NULL ) { + printf( "IOServiceMatching returned a NULL dictionary.\n" ); + } else { + CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); + } + kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); + if ( KERN_SUCCESS != kernResult ) + { + printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); + } + + return kernResult; +} + +kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) +{ + io_object_t nextMedia; + kern_return_t kernResult = KERN_FAILURE; + *bsdPath = '\0'; + nextMedia = IOIteratorNext( mediaIterator ); + if ( nextMedia ) + { + CFTypeRef bsdPathAsCFString; + bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); + if ( bsdPathAsCFString ) { + size_t devPathLength; + strcpy( bsdPath, _PATH_DEV ); + strcat( bsdPath, "r" ); + devPathLength = strlen( bsdPath ); + if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { + kernResult = KERN_SUCCESS; + } + CFRelease( bsdPathAsCFString ); + } + IOObjectRelease( nextMedia ); + } + + return kernResult; +} + +#endif + +static int hdev_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + int fd, open_flags, ret; + +#ifdef CONFIG_COCOA + if (strstart(filename, "/dev/cdrom", NULL)) { + kern_return_t kernResult; + io_iterator_t mediaIterator; + char bsdPath[ MAXPATHLEN ]; + int fd; + + kernResult = FindEjectableCDMedia( &mediaIterator ); + kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); + + if ( bsdPath[ 0 ] != '\0' ) { + strcat(bsdPath,"s0"); + /* some CDs don't have a partition 0 */ + fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) { + bsdPath[strlen(bsdPath)-1] = '1'; + } else { + close(fd); + } + filename = bsdPath; + } + + if ( mediaIterator ) + IOObjectRelease( mediaIterator ); + } +#endif + open_flags = O_BINARY; + if ((flags & BDRV_O_ACCESS) == O_RDWR) { + open_flags |= O_RDWR; + } else { + open_flags |= O_RDONLY; + bs->read_only = 1; + } + + s->type = FTYPE_FILE; +#if defined(__linux__) + if (strstart(filename, "/dev/cd", NULL)) { + /* open will not fail even if no CD is inserted */ + open_flags |= O_NONBLOCK; + s->type = FTYPE_CD; + } else if (strstart(filename, "/dev/fd", NULL)) { + s->type = FTYPE_FD; + s->fd_open_flags = open_flags; + /* open will not fail even if no floppy is inserted */ + open_flags |= O_NONBLOCK; + } +#endif + fd = open(filename, open_flags, 0644); + if (fd < 0) { + ret = -errno; + if (ret == -EROFS) + ret = -EACCES; + return ret; + } + s->fd = fd; +#if defined(__linux__) + /* close fd so that we can reopen it as needed */ + if (s->type == FTYPE_FD) { + close(s->fd); + s->fd = -1; + s->fd_media_changed = 1; + } +#endif + return 0; +} + +static int fd_open(BlockDriverState *bs) +{ + return 0; +} + +#if defined(__linux__) + +static int raw_is_inserted(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + int ret; + + switch(s->type) { + case FTYPE_CD: + ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); + if (ret == CDS_DISC_OK) + return 1; + else + return 0; + break; + case FTYPE_FD: + ret = fd_open(bs); + return (ret >= 0); + default: + return 1; + } +} + +/* currently only used by fdc.c, but a CD version would be good too */ +static int raw_media_changed(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + + switch(s->type) { + case FTYPE_FD: + { + int ret; + /* XXX: we do not have a true media changed indication. It + does not work if the floppy is changed without trying + to read it */ + fd_open(bs); + ret = s->fd_media_changed; + s->fd_media_changed = 0; +#ifdef DEBUG_FLOPPY + printf("Floppy changed=%d\n", ret); +#endif + return ret; + } + default: + return -ENOTSUP; + } +} + +static int raw_eject(BlockDriverState *bs, int eject_flag) +{ + BDRVRawState *s = bs->opaque; + + switch(s->type) { + case FTYPE_CD: + if (eject_flag) { + if (ioctl (s->fd, CDROMEJECT, NULL) < 0) + perror("CDROMEJECT"); + } else { + if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0) + perror("CDROMEJECT"); + } + break; + case FTYPE_FD: + { + int fd; + if (s->fd >= 0) { + close(s->fd); + s->fd = -1; + } + fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); + if (fd >= 0) { + if (ioctl(fd, FDEJECT, 0) < 0) + perror("FDEJECT"); + close(fd); + } + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +static int raw_set_locked(BlockDriverState *bs, int locked) +{ + BDRVRawState *s = bs->opaque; + + switch(s->type) { + case FTYPE_CD: + if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) { + /* Note: an error can happen if the distribution automatically + mounts the CD-ROM */ + // perror("CDROM_LOCKDOOR"); + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +#else + +static int raw_is_inserted(BlockDriverState *bs) +{ + return 1; +} + +static int raw_media_changed(BlockDriverState *bs) +{ + return -ENOTSUP; +} + +static int raw_eject(BlockDriverState *bs, int eject_flag) +{ + return -ENOTSUP; +} + +static int raw_set_locked(BlockDriverState *bs, int locked) +{ + return -ENOTSUP; +} + +#endif /* !linux */ + +BlockDriver bdrv_host_device = { + "host_device", + sizeof(BDRVRawState), + NULL, /* no probe for protocols */ + hdev_open, + NULL, + NULL, + raw_close, + NULL, + raw_flush, + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_getlength = raw_getlength, + + /* removable device support */ + .bdrv_is_inserted = raw_is_inserted, + .bdrv_media_changed = raw_media_changed, + .bdrv_eject = raw_eject, + .bdrv_set_locked = raw_set_locked, +}; + +#else /* _WIN32 */ + +/* XXX: use another file ? */ +#include + +#define FTYPE_FILE 0 +#define FTYPE_CD 1 +#define FTYPE_HARDDISK 2 + +typedef struct BDRVRawState { + HANDLE hfile; + int type; + char drive_path[16]; /* format: "d:\" */ +} BDRVRawState; + +int qemu_ftruncate64(int fd, int64_t length) +{ + LARGE_INTEGER li; + LONG high; + HANDLE h; + BOOL res; + + if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) + return -1; + + h = (HANDLE)_get_osfhandle(fd); + + /* get current position, ftruncate do not change position */ + li.HighPart = 0; + li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); + if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) + return -1; + + high = length >> 32; + if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) + return -1; + res = SetEndOfFile(h); + + /* back to old position */ + SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); + return res ? 0 : -1; +} + +static int set_sparse(int fd) +{ + DWORD returned; + return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, + NULL, 0, NULL, 0, &returned, NULL); +} + +static int raw_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + int access_flags, create_flags; + DWORD overlapped; + + s->type = FTYPE_FILE; + + if ((flags & BDRV_O_ACCESS) == O_RDWR) { + access_flags = GENERIC_READ | GENERIC_WRITE; + } else { + access_flags = GENERIC_READ; + } + if (flags & BDRV_O_CREAT) { + create_flags = CREATE_ALWAYS; + } else { + create_flags = OPEN_EXISTING; + } +#ifdef QEMU_TOOL + overlapped = FILE_ATTRIBUTE_NORMAL; +#else + overlapped = FILE_FLAG_OVERLAPPED; +#endif + s->hfile = CreateFile(filename, access_flags, + FILE_SHARE_READ, NULL, + create_flags, overlapped, NULL); + if (s->hfile == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; + return -1; + } + return 0; +} + +static int raw_pread(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + OVERLAPPED ov; + DWORD ret_count; + int ret; + + memset(&ov, 0, sizeof(ov)); + ov.Offset = offset; + ov.OffsetHigh = offset >> 32; + ret = ReadFile(s->hfile, buf, count, &ret_count, &ov); + if (!ret) { + ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); + if (!ret) + return -EIO; + else + return ret_count; + } + return ret_count; +} + +static int raw_pwrite(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count) +{ + BDRVRawState *s = bs->opaque; + OVERLAPPED ov; + DWORD ret_count; + int ret; + + memset(&ov, 0, sizeof(ov)); + ov.Offset = offset; + ov.OffsetHigh = offset >> 32; + ret = WriteFile(s->hfile, buf, count, &ret_count, &ov); + if (!ret) { + ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); + if (!ret) + return -EIO; + else + return ret_count; + } + return ret_count; +} + +static void raw_flush(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + FlushFileBuffers(s->hfile); +} + +static void raw_close(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + CloseHandle(s->hfile); +} + +static int raw_truncate(BlockDriverState *bs, int64_t offset) +{ + BDRVRawState *s = bs->opaque; + DWORD low, high; + + low = offset; + high = offset >> 32; + if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN)) + return -EIO; + if (!SetEndOfFile(s->hfile)) + return -EIO; + return 0; +} + +static int64_t raw_getlength(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + LARGE_INTEGER l; + ULARGE_INTEGER available, total, total_free; + DISK_GEOMETRY dg; + DWORD count; + BOOL status; + + switch(s->type) { + case FTYPE_FILE: + l.LowPart = GetFileSize(s->hfile, &l.HighPart); + if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) + return -EIO; + break; + case FTYPE_CD: + if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) + return -EIO; + l.QuadPart = total.QuadPart; + break; + case FTYPE_HARDDISK: + status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, 0, &dg, sizeof(dg), &count, NULL); + if (status != FALSE) { + l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder + * dg.SectorsPerTrack * dg.BytesPerSector; + } + break; + default: + return -EIO; + } + return l.QuadPart; +} + +static int raw_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd; + + if (flags || backing_file) + return -ENOTSUP; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + 0644); + if (fd < 0) + return -EIO; + set_sparse(fd); + ftruncate(fd, total_size * 512); + close(fd); + return 0; +} + +BlockDriver bdrv_raw = { + "raw", + sizeof(BDRVRawState), + NULL, /* no probe for protocols */ + raw_open, + NULL, + NULL, + raw_close, + raw_create, + raw_flush, + + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_truncate = raw_truncate, + .bdrv_getlength = raw_getlength, +}; + +/***********************************************/ +/* host device */ + +static int find_cdrom(char *cdrom_name, int cdrom_name_size) +{ + char drives[256], *pdrv = drives; + UINT type; + + memset(drives, 0, sizeof(drives)); + GetLogicalDriveStrings(sizeof(drives), drives); + while(pdrv[0] != '\0') { + type = GetDriveType(pdrv); + switch(type) { + case DRIVE_CDROM: + snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); + return 0; + break; + } + pdrv += lstrlen(pdrv) + 1; + } + return -1; +} + +static int find_device_type(BlockDriverState *bs, const char *filename) +{ + BDRVRawState *s = bs->opaque; + UINT type; + const char *p; + + if (strstart(filename, "\\\\.\\", &p) || + strstart(filename, "//./", &p)) { + if (stristart(p, "PhysicalDrive", NULL)) + return FTYPE_HARDDISK; + snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); + type = GetDriveType(s->drive_path); + if (type == DRIVE_CDROM) + return FTYPE_CD; + else + return FTYPE_FILE; + } else { + return FTYPE_FILE; + } +} + +static int hdev_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + int access_flags, create_flags; + DWORD overlapped; + char device_name[64]; + + if (strstart(filename, "/dev/cdrom", NULL)) { + if (find_cdrom(device_name, sizeof(device_name)) < 0) + return -ENOENT; + filename = device_name; + } else { + /* transform drive letters into device name */ + if (((filename[0] >= 'a' && filename[0] <= 'z') || + (filename[0] >= 'A' && filename[0] <= 'Z')) && + filename[1] == ':' && filename[2] == '\0') { + snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); + filename = device_name; + } + } + s->type = find_device_type(bs, filename); + + if ((flags & BDRV_O_ACCESS) == O_RDWR) { + access_flags = GENERIC_READ | GENERIC_WRITE; + } else { + access_flags = GENERIC_READ; + } + create_flags = OPEN_EXISTING; + +#ifdef QEMU_TOOL + overlapped = FILE_ATTRIBUTE_NORMAL; +#else + overlapped = FILE_FLAG_OVERLAPPED; +#endif + s->hfile = CreateFile(filename, access_flags, + FILE_SHARE_READ, NULL, + create_flags, overlapped, NULL); + if (s->hfile == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; + return -1; + } + return 0; +} + +BlockDriver bdrv_host_device = { + "host_device", + sizeof(BDRVRawState), + NULL, /* no probe for protocols */ + hdev_open, + NULL, + NULL, + raw_close, + NULL, + raw_flush, + + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_getlength = raw_getlength, +}; +#endif /* _WIN32 */ diff --git a/block-vvfat.c b/block-vvfat.c new file mode 100644 index 0000000..33a610b --- /dev/null +++ b/block-vvfat.c @@ -0,0 +1,3045 @@ +/* vim:set shiftwidth=4 ts=8: */ +/* + * QEMU Block driver for virtual VFAT (shadows a local directory) + * + * Copyright (c) 2004,2005 Johannes E. Schindelin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#ifdef QEMU_OLD +#include "vl.h" +#else +#include "qemu-common.h" +#include "block.h" +#endif +#include "block_int.h" + +#ifndef S_IWGRP +#define S_IWGRP 0 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0 +#endif + +/* TODO: add ":bootsector=blabla.img:" */ +/* LATER TODO: add automatic boot sector generation from + BOOTEASY.ASM and Ranish Partition Manager + Note that DOS assumes the system files to be the first files in the + file system (test if the boot sector still relies on that fact)! */ +/* MAYBE TODO: write block-visofs.c */ + +#define DEBUG +#undef DEBUG_SECTORS + +#ifdef DEBUG + +#define DLOG(a) a + +#undef stderr +#define stderr STDERR +FILE* stderr = NULL; + +static void checkpoint(const char *where); + +#ifdef __MINGW32__ +void nonono(const char* file, int line, const char* msg) { + fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg); + exit(-5); +} +#undef assert +#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0) +#endif + +#else + +#define DLOG(a) + +#endif + +#define VOLUME_LABEL "X49GP-VVFAT" + +/* dynamic array functions */ +typedef struct array_t { + unsigned char* pointer; + unsigned int size,next,item_size; +} array_t; + +static inline void array_init(array_t* array,unsigned int item_size) +{ + array->pointer=0; + array->size=0; + array->next=0; + array->item_size=item_size; +} + +static inline void array_free(array_t* array) +{ + if(array->pointer) + free(array->pointer); + array->size=array->next=0; +} + +/* does not automatically grow */ +static inline void* array_get(array_t* array,unsigned int index) { + assert(index >= 0); + assert(index < array->next); + return array->pointer + index * array->item_size; +} + +static inline int array_ensure_allocated(array_t* array, int index) +{ + if((index + 1) * array->item_size > array->size) { + int new_size = (index + 32) * array->item_size; + array->pointer = realloc(array->pointer, new_size); + if (!array->pointer) + return -1; + array->size = new_size; + array->next = index + 1; + } + + return 0; +} + +static inline void* array_get_next(array_t* array) { + unsigned int next = array->next; + void* result; + + if (array_ensure_allocated(array, next) < 0) + return NULL; + + array->next = next + 1; + result = array_get(array, next); + + return result; +} + +static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) { + if((array->next+count)*array->item_size>array->size) { + int increment=count*array->item_size; + array->pointer=realloc(array->pointer,array->size+increment); + if(!array->pointer) + return 0; + array->size+=increment; + } + memmove(array->pointer+(index+count)*array->item_size, + array->pointer+index*array->item_size, + (array->next-index)*array->item_size); + array->next+=count; + return array->pointer+index*array->item_size; +} + +/* this performs a "roll", so that the element which was at index_from becomes + * index_to, but the order of all other elements is preserved. */ +static inline int array_roll(array_t* array,int index_to,int index_from,int count) +{ + unsigned char* buf; + unsigned char* from; + unsigned char* to; + int is; + + if(!array || + index_to<0 || index_to>=array->next || + index_from<0 || index_from>=array->next) + return -1; + + if(index_to==index_from) + return 0; + + is=array->item_size; + from=array->pointer+index_from*is; + to=array->pointer+index_to*is; + buf=malloc(is*count); + memcpy(buf,from,is*count); + + if(index_to=0); + assert(count > 0); + assert(index + count <= array->next); + if(array_roll(array,array->next-1,index,count)) + return -1; + array->next -= count; + return 0; +} + +static int array_remove(array_t* array,int index) +{ + return array_remove_slice(array, index, 1); +} + +/* return the index for a given member */ +static int array_index(array_t* array, void* pointer) +{ + size_t offset = (unsigned char*)pointer - array->pointer; + assert(offset >= 0); + assert((offset % array->item_size) == 0); + assert(offset/array->item_size < array->next); + return offset/array->item_size; +} + +/* These structures are used to fake a disk and the VFAT filesystem. + * For this reason we need to use __attribute__((packed)). */ + +#define BOOTCODE_SIZE 448 +#define BOOTCODE_FAT32_SIZE 420 + +typedef struct msdos_volume_info { + uint8_t drive_number; + uint8_t ignored; + uint8_t signature; + uint32_t id; + uint8_t volume_label[11]; + uint8_t fs_type[8]; +} __attribute__((packed)) msdos_volume_info_t; + +typedef struct bootsector_t { + uint8_t jump[3]; + uint8_t name[8]; + uint16_t sector_size; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t number_of_fats; + uint16_t root_entries; + uint16_t total_sectors16; + uint8_t media_type; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t number_of_heads; + uint32_t hidden_sectors; + uint32_t total_sectors; + union { + struct { + msdos_volume_info_t vi; + uint8_t boot_code[BOOTCODE_SIZE]; + } __attribute__((packed)) fat16; + struct { + uint32_t sectors_per_fat; + uint16_t flags; + uint8_t major,minor; + uint32_t first_cluster_of_root_directory; + uint16_t info_sector; + uint16_t backup_boot_sector; + uint16_t ignored[6]; + msdos_volume_info_t vi; + uint8_t boot_code[BOOTCODE_FAT32_SIZE]; + } __attribute__((packed)) fat32; + } u; + uint8_t magic[2]; +} __attribute__((packed)) bootsector_t; + +static +uint8_t dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 }; + +static +uint8_t dummy_boot_code[BOOTCODE_SIZE] = + "\x0e" /* push cs */ + "\x1f" /* pop ds */ + "\xbe\x5b\x7c" /* mov si, */ +/* write_msg: */ + "\xac" /* lodsb */ + "\x22\xc0" /* and al, al */ + "\x74\x0b" /* jz key_press */ + "\x56" /* push si */ + "\xb4\x0e" /* mov ah, 0eh */ + "\xbb\x07\x00" /* mov bx, 0007h */ + "\xcd\x10" /* int 10h */ + "\x5e" /* pop si */ + "\xeb\xf0" /* jmp write_msg */ +/* key_press: */ + "\x32\xe4" /* xor ah, ah */ + "\xcd\x16" /* int 16h */ + "\xcd\x19" /* int 19h */ +/* foo: */ + "\xeb\xfe" /* jmp foo */ +/* message_text: */ + "This is not a bootable disk. Please insert a bootable floppy and\r\n" + "press any key to try again...\r\n"; + +#define MSG_OFFSET_OFFSET 3 +#define MESSAGE_OFFSET 29 /* Offset of message in above code */ + +typedef struct partition_t { + uint8_t attributes; /* 0x80 = bootable */ + uint8_t start_head; + uint8_t start_sector; + uint8_t start_cylinder; + uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */ + uint8_t end_head; + uint8_t end_sector; + uint8_t end_cylinder; + uint32_t start_sector_long; + uint32_t end_sector_long; +} __attribute__((packed)) partition_t; + +typedef struct mbr_t { + uint8_t ignored[0x1be]; + partition_t partition[4]; + uint8_t magic[2]; +} __attribute__((packed)) mbr_t; + +typedef struct direntry_t { + uint8_t name[8]; + uint8_t extension[3]; + uint8_t attributes; + uint8_t reserved[2]; + uint16_t ctime; + uint16_t cdate; + uint16_t adate; + uint16_t begin_hi; + uint16_t mtime; + uint16_t mdate; + uint16_t begin; + uint32_t size; +} __attribute__((packed)) direntry_t; + +/* this structure are used to transparently access the files */ + +typedef struct mapping_t { + /* begin is the first cluster, end is the last+1 */ + uint32_t begin,end; + /* as s->directory is growable, no pointer may be used here */ + unsigned int dir_index; + /* the clusters of a file may be in any order; this points to the first */ + int first_mapping_index; + union { + /* offset is + * - the offset in the file (in clusters) for a file, or + * - the next cluster of the directory for a directory, and + * - the address of the buffer for a faked entry + */ + struct { + uint32_t offset; + } file; + struct { + int parent_mapping_index; + int first_dir_index; + } dir; + } info; + /* path contains the full path, i.e. it always starts with s->path */ + char* path; + + enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2, + MODE_DIRECTORY = 4, MODE_FAKED = 8, + MODE_DELETED = 16, MODE_RENAMED = 32 } mode; + int read_only; +} mapping_t; + +#ifdef DEBUG +static void print_direntry(const struct direntry_t*); +static void print_mapping(const struct mapping_t* mapping); +#endif + +/* here begins the real VVFAT driver */ + +typedef struct BDRVVVFATState { + BlockDriverState* bs; /* pointer to parent */ + unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */ + unsigned char first_sectors[0x40*0x200]; + + int fat_type; /* 16 or 32 */ + array_t fat,directory,mapping; + + unsigned int cluster_size; + unsigned int sectors_per_cluster; + unsigned int sectors_per_fat; + unsigned int sectors_of_root_directory; + uint32_t last_cluster_of_root_directory; + unsigned int faked_sectors; /* how many sectors are faked before file data */ + uint32_t sector_count; /* total number of sectors of the partition */ + uint32_t cluster_count; /* total number of clusters of this partition */ + uint32_t max_fat_value; + + int current_fd; + mapping_t* current_mapping; + unsigned char* cluster; /* points to current cluster */ + unsigned char* cluster_buffer; /* points to a buffer to hold temp data */ + unsigned int current_cluster; + + /* write support */ + char* qcow_filename; + BlockDriverState* qcow; + void* fat2; + char* used_clusters; + array_t commits; + const char* path; + int downcase_short_names; + QEMUTimer *write_timer; +} BDRVVVFATState; + + +static void init_mbr(BDRVVVFATState* s) +{ + /* TODO: if the files mbr.img and bootsect.img exist, use them */ + mbr_t* real_mbr=(mbr_t*)s->first_sectors; + partition_t* partition=&(real_mbr->partition[0]); + + memset(s->first_sectors,0,512); + + partition->attributes=0x80; /* bootable */ + partition->start_head=1; + partition->start_sector=1; + partition->start_cylinder=0; + /* FAT12/FAT16/FAT32 */ + partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb); + partition->end_head=s->bs->heads-1; + partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */; + partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */; + partition->start_sector_long=cpu_to_le32(s->bs->secs); + partition->end_sector_long=cpu_to_le32(s->sector_count); + + real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; +} + +/* direntry functions */ + +/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */ +static inline int short2long_name(char* dest,const char* src) +{ + int i; + for(i=0;i<129 && src[i];i++) { + dest[2*i]=src[i]; + dest[2*i+1]=0; + } + dest[2*i]=dest[2*i+1]=0; + for(i=2*i+2;(i%26);i++) + dest[i]=0xff; + return i; +} + +static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename) +{ + char buffer[258]; + int length=short2long_name(buffer,filename), + number_of_entries=(length+25)/26,i; + direntry_t* entry; + + for(i=0;idirectory)); + entry->attributes=0xf; + entry->reserved[0]=0; + entry->begin=0; + entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); + } + for(i=0;idirectory),s->directory.next-1-(i/26)); + entry->name[offset]=buffer[i]; + } + return array_get(&(s->directory),s->directory.next-number_of_entries); +} + +static char is_free(const direntry_t* direntry) +{ + /* return direntry->name[0]==0 ; */ + return direntry->attributes == 0 || direntry->name[0]==0xe5; +} + +static char is_volume_label(const direntry_t* direntry) +{ + return (direntry->attributes & 0x1f) == 0x08; +} + +static char is_long_name(const direntry_t* direntry) +{ + return direntry->attributes == 0xf; +} + +static char is_short_name(const direntry_t* direntry) +{ + return !is_volume_label(direntry) && !is_long_name(direntry) + && !is_free(direntry); +} + +static char is_directory(const direntry_t* direntry) +{ + return direntry->attributes & 0x10 && direntry->name[0] != 0xe5; +} + +static inline char is_dot(const direntry_t* direntry) +{ + return is_short_name(direntry) && direntry->name[0] == '.'; +} + +static char is_file(const direntry_t* direntry) +{ + return is_short_name(direntry) && !is_directory(direntry); +} + +static inline uint32_t begin_of_direntry(const direntry_t* direntry) +{ + return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16); +} + +static inline uint32_t filesize_of_direntry(const direntry_t* direntry) +{ + return le32_to_cpu(direntry->size); +} + +static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin) +{ + direntry->begin = cpu_to_le16(begin & 0xffff); + direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff); +} + +/* fat functions */ + +static inline uint8_t fat_chksum(const direntry_t* entry) +{ + uint8_t chksum=0; + int i; + + for(i=0;i<11;i++) + chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + +(unsigned char)entry->name[i]; + + return chksum; +} + +/* if return_time==0, this returns the fat_date, else the fat_time */ +static uint16_t fat_datetime(time_t time,int return_time) { + struct tm* t; +#ifdef _WIN32 + t=localtime(&time); /* this is not thread safe */ +#else + struct tm t1; + t=&t1; + localtime_r(&time,t); +#endif + if(return_time) + return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); + return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9)); +} + +static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value) +{ + if(s->fat_type==32) { + uint32_t* entry=array_get(&(s->fat),cluster); + DLOG(fprintf(stderr, "%s:%u: cluster %u: %08x\n", __FUNCTION__, __LINE__, cluster, value)); + *entry=cpu_to_le32(value); + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); + DLOG(fprintf(stderr, "%s:%u: cluster %u: %04x\n", __FUNCTION__, __LINE__, cluster, value & 0xffff)); + *entry=cpu_to_le16(value&0xffff); + } else { + int offset = (cluster*3/2); + unsigned char* p = array_get(&(s->fat), offset); + DLOG(fprintf(stderr, "%s:%u: cluster %u: %03x\n", __FUNCTION__, __LINE__, cluster, value & 0xfff)); + switch (cluster&1) { + case 0: + p[0] = value&0xff; + p[1] = (p[1]&0xf0) | ((value>>8)&0xf); + break; + case 1: + p[0] = (p[0]&0xf) | ((value&0xf)<<4); + p[1] = (value>>4); + break; + } + } +} + +static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster) +{ + if(s->fat_type==32) { + uint32_t* entry=array_get(&(s->fat),cluster); + return le32_to_cpu(*entry); + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); + return le16_to_cpu(*entry); + } else { + const uint8_t* x=s->fat.pointer+cluster*3/2; + return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; + } +} + +static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry) +{ + if(fat_entry>s->max_fat_value-8) + return -1; + return 0; +} + +static inline void init_fat(BDRVVVFATState* s) +{ + if (s->fat_type == 12) { + array_init(&(s->fat),1); + array_ensure_allocated(&(s->fat), + s->sectors_per_fat * 0x200 * 3 / 2 - 1); + } else { + array_init(&(s->fat),(s->fat_type==32?4:2)); + array_ensure_allocated(&(s->fat), + s->sectors_per_fat * 0x200 / s->fat.item_size - 1); + } + memset(s->fat.pointer,0,s->fat.size); + + switch(s->fat_type) { + case 12: s->max_fat_value=0xfff; break; + case 16: s->max_fat_value=0xffff; break; + case 32: s->max_fat_value=0x0fffffff; break; + default: s->max_fat_value=0; /* error... */ + } +} + +/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ +/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */ +static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, + unsigned int directory_start, const char* filename, int is_dot) +{ + int i,j,long_index=s->directory.next; + direntry_t* entry=0; + direntry_t* entry_long=0; + + if(is_dot) { + entry=array_get_next(&(s->directory)); + memset(entry->name,' ',11); + memcpy(entry->name,filename,strlen(filename)); + return entry; + } + + entry_long=create_long_filename(s,filename); + + i = strlen(filename); + for(j = i - 1; j>0 && filename[j]!='.';j--); + if (j > 0) + i = (j > 8 ? 8 : j); + else if (i > 8) + i = 8; + + entry=array_get_next(&(s->directory)); + memset(entry->name,' ',11); + strncpy((char *) entry->name,filename,i); + + if(j > 0) + for (i = 0; i < 3 && filename[j+1+i]; i++) + entry->extension[i] = filename[j+1+i]; + + /* upcase & remove unwanted characters */ + for(i=10;i>=0;i--) { + if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--); + if(entry->name[i]<=' ' || entry->name[i]>0x7f + || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) + entry->name[i]='_'; + else if(entry->name[i]>='a' && entry->name[i]<='z') + entry->name[i]+='A'-'a'; + } + + /* mangle duplicates */ + while(1) { + direntry_t* entry1=array_get(&(s->directory),directory_start); + int j; + + for(;entry1name,entry->name,11)) + break; /* found dupe */ + if(entry1==entry) /* no dupe found */ + break; + + /* use all 8 characters of name */ + if(entry->name[7]==' ') { + int j; + for(j=6;j>0 && entry->name[j]==' ';j--) + entry->name[j]='~'; + } + + /* increment number */ + for(j=7;j>0 && entry->name[j]=='9';j--) + entry->name[j]='0'; + if(j>0) { + if(entry->name[j]<'0' || entry->name[j]>'9') + entry->name[j]='0'; + else + entry->name[j]++; + } + } + + /* calculate checksum; propagate to long name */ + if(entry_long) { + uint8_t chksum=fat_chksum(entry); + + /* calculate anew, because realloc could have taken place */ + entry_long=array_get(&(s->directory),long_index); + while(entry_longreserved[1]=chksum; + entry_long++; + } + } + + return entry; +} + +/* + * Read a directory. (the index of the corresponding mapping must be passed). + */ +static int read_directory(BDRVVVFATState* s, int mapping_index) +{ + mapping_t* mapping = array_get(&(s->mapping), mapping_index); + direntry_t* direntry; + const char* dirname = mapping->path; + int first_cluster = mapping->begin; + int parent_index = mapping->info.dir.parent_mapping_index; + mapping_t* parent_mapping = (mapping_t*) + (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0); + int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1; + + DIR* dir=opendir(dirname); + struct dirent* entry; + int i; + + assert(mapping->mode & MODE_DIRECTORY); + + if(!dir) { + mapping->end = mapping->begin; + return -1; + } + + i = mapping->info.dir.first_dir_index = + first_cluster == 0 ? 0 : s->directory.next; + + /* actually read the directory, and allocate the mappings */ + while((entry=readdir(dir))) { + unsigned int length=strlen(dirname)+2+strlen(entry->d_name); + char* buffer; + direntry_t* direntry; + struct stat st; + int is_dot=!strcmp(entry->d_name,"."); + int is_dotdot=!strcmp(entry->d_name,".."); + + if(first_cluster == 0 && (is_dotdot || is_dot)) + continue; + + buffer=(char*)malloc(length); + assert(buffer); + snprintf(buffer,length,"%s/%s",dirname,entry->d_name); + + if(stat(buffer,&st)<0) { + free(buffer); + continue; + } + + DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); + + /* create directory entry for this file */ + direntry=create_short_and_long_name(s, i, entry->d_name, + is_dot || is_dotdot); + direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); + direntry->reserved[0]=direntry->reserved[1]=0; + direntry->ctime=fat_datetime(st.st_ctime,1); + direntry->cdate=fat_datetime(st.st_ctime,0); + direntry->adate=fat_datetime(st.st_atime,0); + direntry->begin_hi=0; + direntry->mtime=fat_datetime(st.st_mtime,1); + direntry->mdate=fat_datetime(st.st_mtime,0); + if(is_dotdot) + set_begin_of_direntry(direntry, first_cluster_of_parent); + else if(is_dot) + set_begin_of_direntry(direntry, first_cluster); + else + direntry->begin=0; /* do that later */ + if (st.st_size > 0x7fffffff) { + fprintf(stderr, "File %s is larger than 2GB\n", buffer); + free(buffer); + return -2; + } + direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size); + + /* create mapping for this file */ + if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { + DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); + + s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); + s->current_mapping->begin=0; + s->current_mapping->end=st.st_size; + /* + * we get the direntry of the most recent direntry, which + * contains the short name and all the relevant information. + */ + s->current_mapping->dir_index=s->directory.next-1; + s->current_mapping->first_mapping_index = -1; + if (S_ISDIR(st.st_mode)) { + s->current_mapping->mode = MODE_DIRECTORY; + s->current_mapping->info.dir.parent_mapping_index = + mapping_index; + } else { + s->current_mapping->mode = MODE_UNDEFINED; + s->current_mapping->info.file.offset = 0; + } + s->current_mapping->path=buffer; + s->current_mapping->read_only = + (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; + } + } + closedir(dir); + + /* fill with zeroes up to the end of the cluster */ + while(s->directory.next%(0x10*s->sectors_per_cluster)) { + direntry_t* direntry=array_get_next(&(s->directory)); + memset(direntry,0,sizeof(direntry_t)); + } + +/* TODO: if there are more entries, bootsector has to be adjusted! */ +#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster) + if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) { + /* root directory */ + int cur = s->directory.next; + array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); + memset(array_get(&(s->directory), cur), 0, + (ROOT_ENTRIES - cur) * sizeof(direntry_t)); + } + + /* reget the mapping, since s->mapping was possibly realloc()ed */ + mapping = (mapping_t*)array_get(&(s->mapping), mapping_index); + first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) + * 0x20 / s->cluster_size; + mapping->end = first_cluster; + + direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index); + set_begin_of_direntry(direntry, mapping->begin); + + return 0; +} + +static inline int32_t sector2cluster(BDRVVVFATState* s, off_t sector_num) +{ + return (sector_num - s->faked_sectors) / s->sectors_per_cluster; +} + +static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) +{ + return s->faked_sectors + s->sectors_per_cluster * cluster_num; +} + +static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num) +{ + return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster; +} + +#ifdef DBG +static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping) +{ + if(mapping->mode==MODE_UNDEFINED) + return 0; + return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index); +} +#endif + +static int init_directories(BDRVVVFATState* s, + const char* dirname) +{ + msdos_volume_info_t *vi; + bootsector_t* bootsector; + mapping_t* mapping; + unsigned int i; + unsigned int cluster; + direntry_t *entry; + struct stat st; + size_t namelen; + + memset(&(s->first_sectors[0]),0,0x40*0x200); + + s->cluster_size = s->sectors_per_cluster * 0x200; + s->cluster_buffer = malloc(s->cluster_size); + assert(s->cluster_buffer); + + /* + * The formula: sc = spf+1+spf*spc*(512*8/fat_type), + * where sc is sector_count, + * spf is sectors_per_fat, + * spc is sectors_per_clusters, and + * fat_type = 12, 16 or 32. + */ + i = 1 + s->sectors_per_cluster * 0x200 * 8 / s->fat_type; + s->sectors_per_fat = (s->sector_count + i) / i; /* round up */ + + array_init(&(s->mapping),sizeof(mapping_t)); + array_init(&(s->directory),sizeof(direntry_t)); + + DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, dirname)); + + /* add volume label */ + stat(dirname, &st); + entry = array_get_next(&(s->directory)); + entry->attributes = 0x08; /* archive | volume label */ + memset(entry->name, ' ', 11); + namelen = strlen(VOLUME_LABEL); + if (namelen > 11) + namelen = 11; + memcpy(entry->name, VOLUME_LABEL, namelen); + entry->reserved[0] = entry->reserved[1] = 0; + entry->ctime = fat_datetime(st.st_ctime, 1); + entry->cdate = fat_datetime(st.st_ctime, 0); + entry->adate = fat_datetime(st.st_atime, 0); + entry->begin_hi = 0; + entry->mtime = fat_datetime(st.st_ctime, 1); + entry->mdate = fat_datetime(st.st_ctime, 0); + entry->begin = 0; + entry->size = 0; + + /* Now build FAT, and write back information into directory */ + init_fat(s); + + s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2; + s->cluster_count=sector2cluster(s, s->sector_count); + + DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, dirname)); + + mapping = array_get_next(&(s->mapping)); + mapping->begin = 0; + mapping->dir_index = 0; + mapping->info.dir.parent_mapping_index = -1; + mapping->first_mapping_index = -1; + mapping->path = strdup(dirname); + i = strlen(mapping->path); + if (i > 0 && mapping->path[i - 1] == '/') + mapping->path[i - 1] = '\0'; + mapping->mode = MODE_DIRECTORY; + mapping->read_only = 0; + s->path = mapping->path; + + for (i = 0, cluster = 0; i < s->mapping.next; i++) { + int j; + /* MS-DOS expects the FAT to be 0 for the root directory + * (except for the media byte). */ + /* LATER TODO: still true for FAT32? */ + int fix_fat = (i != 0); + mapping = array_get(&(s->mapping), i); + + if (mapping->mode & MODE_DIRECTORY) { + mapping->begin = cluster; + if(read_directory(s, i)) { + fprintf(stderr, "Could not read directory %s\n", + mapping->path); + return -1; + } + mapping = array_get(&(s->mapping), i); + } else { + assert(mapping->mode == MODE_UNDEFINED); + mapping->mode=MODE_NORMAL; + mapping->begin = cluster; + if (mapping->end > 0) { + direntry_t* direntry = array_get(&(s->directory), + mapping->dir_index); + + mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size; + set_begin_of_direntry(direntry, mapping->begin); + } else { + mapping->end = cluster + 1; + fix_fat = 0; + } + } + + assert(mapping->begin < mapping->end); + + /* fix fat for entry */ + if (fix_fat) { + for(j = mapping->begin; j < mapping->end - 1; j++) + fat_set(s, j, j+1); + fat_set(s, mapping->end - 1, s->max_fat_value); + } + + /* next free cluster */ + cluster = mapping->end; + + if(cluster > s->cluster_count) { + fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type); + return -1; + } + } + + mapping = array_get(&(s->mapping), 0); + s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster; + s->last_cluster_of_root_directory = mapping->end; + + /* the FAT signature */ + switch (s->fat_type) { + case 12: fat_set(s, 0, s->sector_count == 5760 ? 0xff9 : 0xff8); break; + case 16: fat_set(s, 0, 0xfff8); break; + case 32: fat_set(s, 0, 0x0ffffff0); break; + default: fat_set(s,0,s->max_fat_value); break; + } + fat_set(s,1,s->max_fat_value); + + s->current_mapping = NULL; + + bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200); + + memcpy(bootsector->jump, dummy_boot_jump, 3); + bootsector->jump[1] = ((s->fat_type == 32 ? + (char *) &bootsector->u.fat32.boot_code : + (char *) &bootsector->u.fat16.boot_code) - + (char *) &bootsector) - 2; + if (s->fat_type == 32) { + int offset = (char *) &bootsector->u.fat32.boot_code - + (char *) &bootsector + MESSAGE_OFFSET + 0x7c00; + memcpy(bootsector->u.fat32.boot_code, dummy_boot_code, + BOOTCODE_FAT32_SIZE); + bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 0] = offset & 0xff; + bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 1] = offset >> 8; + } else { + memcpy(bootsector->u.fat16.boot_code, dummy_boot_code, BOOTCODE_SIZE); + } + + memcpy(bootsector->name,"X49GP ",8); + bootsector->sector_size=cpu_to_le16(0x200); + bootsector->sectors_per_cluster=s->sectors_per_cluster; + bootsector->reserved_sectors=cpu_to_le16(1); + bootsector->number_of_fats=0x2; /* number of FATs */ + bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); + bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); + bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */ + bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); + bootsector->sectors_per_track=cpu_to_le16(s->bs->secs); + bootsector->number_of_heads=cpu_to_le16(s->bs->heads); + bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f); + bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); + + /* LATER TODO: if FAT32, this is wrong */ + if (s->fat_type == 32) { + vi = &bootsector->u.fat32.vi; + memcpy(vi->fs_type, "FAT32 ", 8); + } else { + vi = &bootsector->u.fat16.vi; + memcpy(vi->fs_type, (s->fat_type == 12 ? "FAT12 " : "FAT16 "), 8); + } + + /* assume this is hda (TODO) */ + vi->drive_number = s->fat_type == 12 ? 0 : 0x80; + vi->signature = 0x29; + vi->id = cpu_to_le32(0xfabe1afd); + memset(vi->volume_label, ' ', 11); + namelen = strlen(VOLUME_LABEL); + if (namelen > 11) + namelen = 11; + memcpy(vi->volume_label, VOLUME_LABEL, namelen); + + bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; + return 0; +} + +#ifdef DEBUG +static BDRVVVFATState *vvv = NULL; +#endif + +static int enable_write(BDRVVVFATState *s); +static int is_consistent(BDRVVVFATState *s); + +static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags) +{ + BDRVVVFATState *s = bs->opaque; + int floppy = 0; + int i; + +#ifdef DEBUG + vvv = s; +#endif + + DLOG(if (stderr == NULL) { + stderr = fopen("vvfat.log", "a"); + setbuf(stderr, NULL); + }) + + s->bs = bs; + + s->fat_type=16; + /* LATER TODO: if FAT32, adjust */ + s->sector_count=0xec04f; + s->sectors_per_cluster=0x10; + /* LATER TODO: this could be wrong for FAT32 */ + bs->cyls=1023; bs->heads=15; bs->secs=63; + + s->current_cluster=0xffffffff; + + s->first_sectors_number=0x40; + /* read only is the default for safety */ + bs->read_only = 1; + s->qcow = NULL; + s->qcow_filename = NULL; + s->fat2 = NULL; + s->downcase_short_names = 1; + + if (!strstart(dirname, "fat:", NULL)) { + DLOG(fprintf(stderr, "%s:%u: dirname '%s' not \"fat:\"\n", __FUNCTION__, __LINE__, dirname)); + return -1; + } + + if (strstr(dirname, ":rw:")) { + if (enable_write(s)) { + return -1; + } + bs->read_only = 0; + } + + if (strstr(dirname, ":floppy:")) { + floppy = 1; + s->fat_type = 12; + s->first_sectors_number = 1; + s->sectors_per_cluster=2; + bs->cyls = 80; bs->heads = 2; bs->secs = 36; + } + + if (strstr(dirname, ":32:")) { + fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); + s->fat_type = 32; + } else if (strstr(dirname, ":16:")) { + s->fat_type = 16; + } else if (strstr(dirname, ":12:")) { + s->fat_type = 12; + s->sector_count=2880; + } + + i = strrchr(dirname, ':') - dirname; + assert(i >= 3); + if (dirname[i-2] == ':' && isalpha(dirname[i-1])) + /* workaround for DOS drive names */ + dirname += i-1; + else + dirname += i+1; + + bs->total_sectors=bs->cyls*bs->heads*bs->secs; + if (s->sector_count > bs->total_sectors) + s->sector_count = bs->total_sectors; + + if (init_directories(s, dirname)) { + DLOG(fprintf(stderr, "%s:%u: init_directories failed\n", __FUNCTION__, __LINE__)); + return -1; + } + + if(s->first_sectors_number==0x40) + init_mbr(s); + + /* for some reason or other, MS-DOS does not like to know about CHS... */ + if (floppy) + bs->heads = bs->cyls = bs->secs = 0; + + // assert(is_consistent(s)); + + DLOG(fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__)); + return 0; +} + +static inline void vvfat_close_current_file(BDRVVVFATState *s) +{ + if(s->current_mapping) { + s->current_mapping = NULL; + if (s->current_fd) { + close(s->current_fd); + s->current_fd = 0; + } + } + s->current_cluster = -1; +} + +/* mappings between index1 and index2-1 are supposed to be ordered + * return value is the index of the last mapping for which end>cluster_num + */ +static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2) +{ + int index3=index1+1; + while(1) { + mapping_t* mapping; + index3=(index1+index2)/2; + mapping=array_get(&(s->mapping),index3); + assert(mapping->begin < mapping->end); + if(mapping->begin>=cluster_num) { + assert(index2!=index3 || index2==0); + if(index2==index3) + return index1; + index2=index3; + } else { + if(index1==index3) + return mapping->end<=cluster_num ? index2 : index1; + index1=index3; + } + assert(index1<=index2); + DLOG(mapping=array_get(&(s->mapping),index1); + assert(mapping->begin<=cluster_num); + assert(index2 >= s->mapping.next || + ((mapping = array_get(&(s->mapping),index2)) && + mapping->end>cluster_num))); + } +} + +static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num) +{ + int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next); + mapping_t* mapping; + if(index>=s->mapping.next) + return 0; + mapping=array_get(&(s->mapping),index); + if(mapping->begin>cluster_num) + return 0; + assert(mapping->begin<=cluster_num && mapping->end>cluster_num); + return mapping; +} + +/* + * This function simply compares path == mapping->path. Since the mappings + * are sorted by cluster, this is expensive: O(n). + */ +static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s, + const char* path) +{ + int i; + + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->first_mapping_index < 0 && + !strcmp(path, mapping->path)) + return mapping; + } + + return NULL; +} + +static int open_file(BDRVVVFATState* s,mapping_t* mapping) +{ + if(!mapping) + return -1; + if(!s->current_mapping || + strcmp(s->current_mapping->path,mapping->path)) { + /* open file */ + int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE); + if(fd<0) + return -1; + vvfat_close_current_file(s); + s->current_fd = fd; + s->current_mapping = mapping; + } + return 0; +} + +static inline int read_cluster(BDRVVVFATState *s,int cluster_num) +{ + if(s->current_cluster != cluster_num) { + int result=0; + off_t offset; + assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY)); + if(!s->current_mapping + || s->current_mapping->begin>cluster_num + || s->current_mapping->end<=cluster_num) { + /* binary search of mappings for file */ + mapping_t* mapping=find_mapping_for_cluster(s,cluster_num); + + assert(!mapping || (cluster_num>=mapping->begin && cluster_numend)); + + if (mapping && mapping->mode & MODE_DIRECTORY) { + vvfat_close_current_file(s); + s->current_mapping = mapping; +read_cluster_directory: + offset = s->cluster_size*(cluster_num-s->current_mapping->begin); + s->cluster = s->directory.pointer+offset + + 0x20*s->current_mapping->info.dir.first_dir_index; + assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); + assert(s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); + s->current_cluster = cluster_num; + return 0; + } + + if(open_file(s,mapping)) + return -2; + } else if (s->current_mapping->mode & MODE_DIRECTORY) + goto read_cluster_directory; + + assert(s->current_fd); + + offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset; + if(lseek(s->current_fd, offset, SEEK_SET)!=offset) + return -3; + s->cluster=s->cluster_buffer; + result=read(s->current_fd,s->cluster,s->cluster_size); + if(result<0) { + s->current_cluster = -1; + return -1; + } + s->current_cluster = cluster_num; + } + return 0; +} + +#ifdef DEBUG +static void hexdump(const void* address, uint32_t len) +{ + const unsigned char* p = address; + int i, j; + + for (i = 0; i < len; i += 16) { + for (j = 0; j < 16 && i + j < len; j++) + fprintf(stderr, "%02x ", p[i + j]); + for (; j < 16; j++) + fprintf(stderr, " "); + fprintf(stderr, " "); + for (j = 0; j < 16 && i + j < len; j++) + fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]); + fprintf(stderr, "\n"); + } +} + +static void print_direntry(const direntry_t* direntry) +{ + int j = 0; + char buffer[1024]; + + fprintf(stderr, "direntry 0x%p: ", direntry); + if(!direntry) + return; + if(is_long_name(direntry)) { + unsigned char* c=(unsigned char*)direntry; + int i; + for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2) +#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;} + ADD_CHAR(c[i]); + for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2) + ADD_CHAR(c[i]); + for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2) + ADD_CHAR(c[i]); + buffer[j] = 0; + fprintf(stderr, "%s\n", buffer); + } else { + int i; + for(i=0;i<11;i++) + ADD_CHAR(direntry->name[i]); + buffer[j] = 0; + fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n", + buffer, + direntry->attributes, + begin_of_direntry(direntry),le32_to_cpu(direntry->size)); + } + { + unsigned char *p = (void *) direntry; + int i; + + fprintf(stderr, "%p:\t", p); + for (i = 0; i < 16; i++) + fprintf(stderr, " %02x", *p++); + fprintf(stderr, "\n%p:\t", p); + for ( ; i < 32; i++) + fprintf(stderr, " %02x", *p++); + fprintf(stderr, "\n"); + } +} + +static void print_mapping(const mapping_t* mapping) +{ + fprintf(stderr, "mapping (0x%p): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode); + if (mapping->mode & MODE_DIRECTORY) + fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index); + else + fprintf(stderr, "offset = %d\n", mapping->info.file.offset); +} +#endif + +static int vvfat_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVVVFATState *s = bs->opaque; +#ifdef DEBUG_SECTORS + int32_t orig_sector = sector_num; +#endif + int i; + + for(i=0;i= s->sector_count) + return -1; + if (s->qcow) { + int n; + if (s->qcow->drv->bdrv_is_allocated(s->qcow, + sector_num, nb_sectors-i, &n)) { +DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n)); + if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n)) + return -1; + i += n - 1; + sector_num += n - 1; + continue; + } +// DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); + } + if(sector_numfaked_sectors) { + if(sector_numfirst_sectors_number) + memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); + else if(sector_num-s->first_sectors_numbersectors_per_fat) + memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200); + else if(sector_num-s->first_sectors_number-s->sectors_per_fatsectors_per_fat) + memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); + } else { + uint32_t sector=sector_num-s->faked_sectors, + sector_offset_in_cluster=(sector%s->sectors_per_cluster), + cluster_num=sector/s->sectors_per_cluster; + if(read_cluster(s, cluster_num) != 0) { + /* LATER TODO: strict: return -1; */ + memset(buf+i*0x200,0,0x200); + continue; + } + memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); + } + } + +#ifdef DEBUG_SECTORS + for (i = 0; i < nb_sectors; i++) { + fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); + hexdump(buf + i * 0x200, 0x200); + } +#endif + + return 0; +} + +/* LATER TODO: statify all functions */ + +/* + * Idea of the write support (use snapshot): + * + * 1. check if all data is consistent, recording renames, modifications, + * new files and directories (in s->commits). + * + * 2. if the data is not consistent, stop committing + * + * 3. handle renames, and create new files and directories (do not yet + * write their contents) + * + * 4. walk the directories, fixing the mapping and direntries, and marking + * the handled mappings as not deleted + * + * 5. commit the contents of the files + * + * 6. handle deleted files and directories + * + */ + +typedef struct commit_t { + char* path; + union { + struct { uint32_t cluster; } rename; + struct { int dir_index; uint32_t modified_offset; } writeout; + struct { uint32_t first_cluster; } new_file; + struct { uint32_t cluster; } mkdir; + } param; + /* DELETEs and RMDIRs are handled differently: see handle_deletes() */ + enum { + ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR + } action; +} commit_t; + +static void clear_commits(BDRVVVFATState* s) +{ + int i; +DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next)); + for (i = 0; i < s->commits.next; i++) { + commit_t* commit = array_get(&(s->commits), i); + assert(commit->path || commit->action == ACTION_WRITEOUT); + if (commit->action != ACTION_WRITEOUT) { + assert(commit->path); + free(commit->path); + } else + assert(commit->path == NULL); + } + s->commits.next = 0; +} + +static void schedule_rename(BDRVVVFATState* s, + uint32_t cluster, char* new_path) +{ + commit_t* commit = array_get_next(&(s->commits)); + commit->path = new_path; + commit->param.rename.cluster = cluster; + commit->action = ACTION_RENAME; +} + +static void schedule_writeout(BDRVVVFATState* s, + int dir_index, uint32_t modified_offset) +{ + commit_t* commit = array_get_next(&(s->commits)); + commit->path = NULL; + commit->param.writeout.dir_index = dir_index; + commit->param.writeout.modified_offset = modified_offset; + commit->action = ACTION_WRITEOUT; +} + +static void schedule_new_file(BDRVVVFATState* s, + char* path, uint32_t first_cluster) +{ + commit_t* commit = array_get_next(&(s->commits)); + commit->path = path; + commit->param.new_file.first_cluster = first_cluster; + commit->action = ACTION_NEW_FILE; +} + +static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path) +{ + commit_t* commit = array_get_next(&(s->commits)); + commit->path = path; + commit->param.mkdir.cluster = cluster; + commit->action = ACTION_MKDIR; +} + +typedef struct { + char name[1024]; + int checksum, len; + int sequence_number; +} long_file_name; + +static void lfn_init(long_file_name* lfn) +{ + lfn->sequence_number = lfn->len = 0; + lfn->checksum = 0x100; +} + +/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */ +static int parse_long_name(long_file_name* lfn, + const direntry_t* direntry) +{ + int i, j, offset; + const unsigned char* pointer = (const unsigned char*)direntry; + + if (!is_long_name(direntry)) + return 1; + + if (pointer[0] & 0x40) { + lfn->sequence_number = pointer[0] & 0x3f; + lfn->checksum = pointer[13]; + lfn->name[0] = 0; + } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) + return -1; + else if (pointer[13] != lfn->checksum) + return -2; + else if (pointer[12] || pointer[26] || pointer[27]) + return -3; + + offset = 13 * (lfn->sequence_number - 1); + for (i = 0, j = 1; i < 13; i++, j+=2) { + if (j == 11) + j = 14; + else if (j == 26) + j = 28; + + if (pointer[j+1] == 0) + lfn->name[offset + i] = pointer[j]; + else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0) + return -4; + else + lfn->name[offset + i] = 0; + } + + if (pointer[0] & 0x40) + lfn->len = offset + strlen(lfn->name + offset); + + return 0; +} + +/* returns 0 if successful, >0 if no short_name, and <0 on error */ +static int parse_short_name(BDRVVVFATState* s, + long_file_name* lfn, direntry_t* direntry) +{ + int i, j; + + if (!is_short_name(direntry)) + return 1; + + for (j = 7; j >= 0 && direntry->name[j] == ' '; j--); + for (i = 0; i <= j; i++) { + if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f) + return -1; + else if (s->downcase_short_names) + lfn->name[i] = tolower(direntry->name[i]); + else + lfn->name[i] = direntry->name[i]; + } + + for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--); + if (j >= 0) { + lfn->name[i++] = '.'; + lfn->name[i + j + 1] = '\0'; + for (;j >= 0; j--) { + if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f) + return -2; + else if (s->downcase_short_names) + lfn->name[i + j] = tolower(direntry->extension[j]); + else + lfn->name[i + j] = direntry->extension[j]; + } + } else + lfn->name[i + j + 1] = '\0'; + + lfn->len = strlen(lfn->name); + + return 0; +} + +static inline uint32_t modified_fat_get(BDRVVVFATState* s, + unsigned int cluster) +{ + if (cluster < s->last_cluster_of_root_directory) { + if (cluster + 1 == s->last_cluster_of_root_directory) + return s->max_fat_value; + else + return cluster + 1; + } + + if (s->fat_type==32) { + uint32_t* entry=((uint32_t*)s->fat2)+cluster; + return le32_to_cpu(*entry); + } else if (s->fat_type==16) { + uint16_t* entry=((uint16_t*)s->fat2)+cluster; + return le16_to_cpu(*entry); + } else { + const uint8_t* x=s->fat2+cluster*3/2; + return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; + } +} + +static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num) +{ + int was_modified = 0; + int i, dummy; + + if (s->qcow == NULL) + return 0; + + for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) + was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow, + cluster2sector(s, cluster_num) + i, 1, &dummy); + + return was_modified; +} + +static const char* get_basename(const char* path) +{ + char* basename = strrchr(path, '/'); + if (basename == NULL) + return path; + else + return basename + 1; /* strip '/' */ +} + +/* + * The array s->used_clusters holds the states of the clusters. If it is + * part of a file, it has bit 2 set, in case of a directory, bit 1. If it + * was modified, bit 3 is set. + * If any cluster is allocated, but not part of a file or directory, this + * driver refuses to commit. + */ +typedef enum { + USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4 +} used_t; + +/* + * get_cluster_count_for_direntry() not only determines how many clusters + * are occupied by direntry, but also if it was renamed or modified. + * + * A file is thought to be renamed *only* if there already was a file with + * exactly the same first cluster, but a different name. + * + * Further, the files/directories handled by this function are + * assumed to be *not* deleted (and *only* those). + */ +static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, + direntry_t* direntry, const char* path) +{ + /* + * This is a little bit tricky: + * IF the guest OS just inserts a cluster into the file chain, + * and leaves the rest alone, (i.e. the original file had clusters + * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens: + * + * - do_commit will write the cluster into the file at the given + * offset, but + * + * - the cluster which is overwritten should be moved to a later + * position in the file. + * + * I am not aware that any OS does something as braindead, but this + * situation could happen anyway when not committing for a long time. + * Just to be sure that this does not bite us, detect it, and copy the + * contents of the clusters to-be-overwritten into the qcow. + */ + int copy_it = 0; + int was_modified = 0; + int32_t ret = 0; + + uint32_t cluster_num = begin_of_direntry(direntry); + uint32_t offset = 0; + int first_mapping_index = -1; + mapping_t* mapping = NULL; + const char* basename2 = NULL; + + vvfat_close_current_file(s); + + /* the root directory */ + if (cluster_num == 0) + return 0; + + /* write support */ + if (s->qcow) { + basename2 = get_basename(path); + + mapping = find_mapping_for_cluster(s, cluster_num); + + if (mapping) { + const char* basename; + + assert(mapping->mode & MODE_DELETED); + DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + basename = get_basename(mapping->path); + + assert(mapping->mode & MODE_NORMAL); + + /* rename */ + if (strcmp(basename, basename2)) + schedule_rename(s, cluster_num, strdup(path)); + } else if (is_file(direntry)) + /* new file */ + schedule_new_file(s, strdup(path), cluster_num); + else { + assert(0); + return 0; + } + } + + while(1) { + if (s->qcow) { + if (!copy_it && cluster_was_modified(s, cluster_num)) { + if (mapping == NULL || + mapping->begin > cluster_num || + mapping->end <= cluster_num) + mapping = find_mapping_for_cluster(s, cluster_num); + + + if (mapping && + (mapping->mode & MODE_DIRECTORY) == 0) { + + /* was modified in qcow */ + if (offset != mapping->info.file.offset + s->cluster_size + * (cluster_num - mapping->begin)) { + /* offset of this cluster in file chain has changed */ + assert(0); + copy_it = 1; + } else if (offset == 0) { + const char* basename = get_basename(mapping->path); + + if (strcmp(basename, basename2)) + copy_it = 1; + first_mapping_index = array_index(&(s->mapping), mapping); + } + + if (mapping->first_mapping_index != first_mapping_index + && mapping->info.file.offset > 0) { + assert(0); + copy_it = 1; + } + + /* need to write out? */ + if (!was_modified && is_file(direntry)) { + was_modified = 1; + schedule_writeout(s, mapping->dir_index, offset); + } + } + } + + if (copy_it) { + int i, dummy; + /* + * This is horribly inefficient, but that is okay, since + * it is rarely executed, if at all. + */ + int64_t offset = cluster2sector(s, cluster_num); + + vvfat_close_current_file(s); + for (i = 0; i < s->sectors_per_cluster; i++) + if (!s->qcow->drv->bdrv_is_allocated(s->qcow, + offset + i, 1, &dummy)) { + if (vvfat_read(s->bs, + offset, s->cluster_buffer, 1)) + return -1; + if (s->qcow->drv->bdrv_write(s->qcow, + offset, s->cluster_buffer, 1)) + return -2; + } + } + } + + ret++; + if (s->used_clusters[cluster_num] & USED_ANY) + return 0; + s->used_clusters[cluster_num] = USED_FILE; + + cluster_num = modified_fat_get(s, cluster_num); + + if (fat_eof(s, cluster_num)) + return ret; + else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16) + return -1; + + offset += s->cluster_size; + } +} + +/* + * This function looks at the modified data (qcow). + * It returns 0 upon inconsistency or error, and the number of clusters + * used by the directory, its subdirectories and their files. + */ +static int check_directory_consistency(BDRVVVFATState *s, + int cluster_num, const char* path) +{ + int ret = 0; + unsigned char* cluster = malloc(s->cluster_size); + direntry_t* direntries = (direntry_t*)cluster; + mapping_t* mapping = find_mapping_for_cluster(s, cluster_num); + + long_file_name lfn; + int path_len = strlen(path); + char path2[PATH_MAX]; + + assert(path_len < PATH_MAX); /* len was tested before! */ + strcpy(path2, path); + path2[path_len] = '/'; + path2[path_len + 1] = '\0'; + + if (mapping) { + const char* basename = get_basename(mapping->path); + const char* basename2 = get_basename(path); + + assert(mapping->mode & MODE_DIRECTORY); + + assert(mapping->mode & MODE_DELETED); + DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + if (strcmp(basename, basename2)) + schedule_rename(s, cluster_num, strdup(path)); + } else + /* new directory */ + schedule_mkdir(s, cluster_num, strdup(path)); + + lfn_init(&lfn); + do { + int i; + int subret = 0; + + ret++; + + if (s->used_clusters[cluster_num] & USED_ANY) { + fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num); + return 0; + } + s->used_clusters[cluster_num] = USED_DIRECTORY; + +DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num))); + subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster, + s->sectors_per_cluster); + if (subret) { + fprintf(stderr, "Error fetching direntries\n"); + fail: + free(cluster); + return 0; + } + + for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { + int cluster_count; + +DLOG(if (!is_free(direntries + i)) { fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i); }) + + if (is_volume_label(direntries + i) || is_dot(direntries + i) || is_free(direntries + i)) + continue; + + subret = parse_long_name(&lfn, direntries + i); + if (subret < 0) { + fprintf(stderr, "Error in long name\n"); + goto fail; + } + if (subret == 0 || is_free(direntries + i)) + continue; + + if (fat_chksum(direntries+i) != lfn.checksum) { + subret = parse_short_name(s, &lfn, direntries + i); + if (subret < 0) { + fprintf(stderr, "Error in short name (%d)\n", subret); + goto fail; + } + if (subret > 0 || !strcmp(lfn.name, ".") + || !strcmp(lfn.name, "..")) + continue; + } + lfn.checksum = 0x100; /* cannot use long name twice */ + + if (path_len + 1 + lfn.len >= PATH_MAX) { + fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); + goto fail; + } + strcpy(path2 + path_len + 1, lfn.name); + + if (is_directory(direntries + i)) { + if (begin_of_direntry(direntries + i) == 0) { + DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i)); + goto fail; + } + cluster_count = check_directory_consistency(s, + begin_of_direntry(direntries + i), path2); + if (cluster_count == 0) { + DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i)); + goto fail; + } + } else if (is_file(direntries + i)) { + /* check file size with FAT */ + cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2); + if (cluster_count != + (le32_to_cpu(direntries[i].size) + s->cluster_size + - 1) / s->cluster_size) { + DLOG(fprintf(stderr, "Cluster count mismatch\n")); + goto fail; + } + } else + assert(0); /* cluster_count = 0; */ + + ret += cluster_count; + } + + cluster_num = modified_fat_get(s, cluster_num); + } while(!fat_eof(s, cluster_num)); + + free(cluster); + return ret; +} + +/* returns 1 on success */ +static int is_consistent(BDRVVVFATState* s) +{ + int i, check; + int used_clusters_count = 0; + +DLOG(checkpoint(__FUNCTION__)); + + DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); + + /* + * - get modified FAT + * - compare the two FATs (TODO) + * - get buffer for marking used clusters + * - recurse direntries from root (using bs->bdrv_read to make + * sure to get the new data) + * - check that the FAT agrees with the size + * - count the number of clusters occupied by this directory and + * its files + * - check that the cumulative used cluster count agrees with the + * FAT + * - if all is fine, return number of used clusters + */ + if (s->fat2 == NULL) { + int size = 0x200 * s->sectors_per_fat; + s->fat2 = malloc(size); + memcpy(s->fat2, s->fat.pointer, size); + } + check = vvfat_read(s->bs, s->first_sectors_number, + s->fat2, s->sectors_per_fat); + if (check) { + fprintf(stderr, "Could not copy fat\n"); + DLOG(fprintf(stderr, "%s:%u: copy fat failed\n", __FUNCTION__, __LINE__)); + return 0; + } + assert (s->used_clusters); + for (i = 0; i < sector2cluster(s, s->sector_count); i++) + s->used_clusters[i] &= ~USED_ANY; + + clear_commits(s); + + /* mark every mapped file/directory as deleted. + * (check_directory_consistency() will unmark those still present). */ + if (s->qcow) { + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->first_mapping_index < 0) { + DLOG(fprintf(stderr, "%s:%u: mark delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode |= MODE_DELETED; + } + } + } + + used_clusters_count = check_directory_consistency(s, 0, s->path); + if (used_clusters_count <= 0) { + DLOG(fprintf(stderr, "problem in directory\n")); + return 0; + } + + check = s->last_cluster_of_root_directory; + for (i = check; i < sector2cluster(s, s->sector_count); i++) { + if (modified_fat_get(s, i)) { + if(!s->used_clusters[i]) { + DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i)); + return 0; + } + check++; + } + + if (s->used_clusters[i] == USED_ALLOCATED) { + /* allocated, but not used... */ + DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i)); + return 0; + } + } + + if (check != used_clusters_count) { + DLOG(fprintf(stderr, "%s:%u: check: %u, used %u\n", __FUNCTION__, __LINE__, check, used_clusters_count)); + return 0; + } + + DLOG(fprintf(stderr, "%s:%u: return used %u\n", __FUNCTION__, __LINE__, used_clusters_count)); + return used_clusters_count; +} + +static inline void adjust_mapping_indices(BDRVVVFATState* s, + int offset, int adjust) +{ + int i; + + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + +#define ADJUST_MAPPING_INDEX(name) \ + if (mapping->name >= offset) \ + mapping->name += adjust + + ADJUST_MAPPING_INDEX(first_mapping_index); + if (mapping->mode & MODE_DIRECTORY) + ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index); + } +} + +/* insert or update mapping */ +static mapping_t* insert_mapping(BDRVVVFATState* s, + uint32_t begin, uint32_t end) +{ + /* + * - find mapping where mapping->begin >= begin, + * - if mapping->begin > begin: insert + * - adjust all references to mappings! + * - else: adjust + * - replace name + */ + int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next); + mapping_t* mapping = NULL; + mapping_t* first_mapping = array_get(&(s->mapping), 0); + + if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index)) + && mapping->begin < begin) { + mapping->end = begin; + index++; + mapping = array_get(&(s->mapping), index); + } + if (index >= s->mapping.next || mapping->begin > begin) { + mapping = array_insert(&(s->mapping), index, 1); + mapping->path = NULL; + adjust_mapping_indices(s, index, +1); + } + + mapping->begin = begin; + mapping->end = end; + +DLOG(mapping_t* next_mapping; +assert(index + 1 >= s->mapping.next || +((next_mapping = array_get(&(s->mapping), index + 1)) && + next_mapping->begin >= end))); + + DLOG(fprintf(stderr, "insert mapping %u:\n", index); print_mapping(mapping)); + + if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) + s->current_mapping = array_get(&(s->mapping), + s->current_mapping - first_mapping); + + return mapping; +} + +static int remove_mapping(BDRVVVFATState* s, int mapping_index) +{ + mapping_t* mapping = array_get(&(s->mapping), mapping_index); + mapping_t* first_mapping = array_get(&(s->mapping), 0); + + DLOG(fprintf(stderr, "remove mapping %u:\n", mapping_index); print_mapping(mapping)); + + /* free mapping */ + if (mapping->first_mapping_index < 0) + free(mapping->path); + + /* remove from s->mapping */ + array_remove(&(s->mapping), mapping_index); + + /* adjust all references to mappings */ + adjust_mapping_indices(s, mapping_index, -1); + + if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) + s->current_mapping = array_get(&(s->mapping), + s->current_mapping - first_mapping); + + return 0; +} + +static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust) +{ + int i; + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->dir_index >= offset) + mapping->dir_index += adjust; + if ((mapping->mode & MODE_DIRECTORY) && + mapping->info.dir.first_dir_index >= offset) + mapping->info.dir.first_dir_index += adjust; + } +} + +static direntry_t* insert_direntries(BDRVVVFATState* s, + int dir_index, int count) +{ + /* + * make room in s->directory, + * adjust_dirindices + */ + direntry_t* result = array_insert(&(s->directory), dir_index, count); + if (result == NULL) + return NULL; + adjust_dirindices(s, dir_index, count); + return result; +} + +static int remove_direntries(BDRVVVFATState* s, int dir_index, int count) +{ + int ret = array_remove_slice(&(s->directory), dir_index, count); + if (ret) + return ret; + adjust_dirindices(s, dir_index, -count); + return 0; +} + +/* + * Adapt the mappings of the cluster chain starting at first cluster + * (i.e. if a file starts at first_cluster, the chain is followed according + * to the modified fat, and the corresponding entries in s->mapping are + * adjusted) + */ +static int commit_mappings(BDRVVVFATState* s, + uint32_t first_cluster, int dir_index) +{ + mapping_t* mapping = find_mapping_for_cluster(s, first_cluster); + direntry_t* direntry = array_get(&(s->directory), dir_index); + uint32_t cluster = first_cluster; + + vvfat_close_current_file(s); + + assert(mapping); + assert(mapping->begin == first_cluster); + mapping->first_mapping_index = -1; + mapping->dir_index = dir_index; + mapping->mode = (dir_index <= 0 || is_directory(direntry)) ? + MODE_DIRECTORY : MODE_NORMAL; + + while (!fat_eof(s, cluster)) { + uint32_t c, c1; + + for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1; + c = c1, c1 = modified_fat_get(s, c1)); + + c++; + if (c > mapping->end) { + int index = array_index(&(s->mapping), mapping); + int i, max_i = s->mapping.next - index; + for (i = 1; i < max_i && mapping[i].begin < c; i++); + while (--i > 0) + remove_mapping(s, index + 1); + } + assert(mapping == array_get(&(s->mapping), s->mapping.next - 1) + || mapping[1].begin >= c); + mapping->end = c; + + if (!fat_eof(s, c1)) { + int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next); + mapping_t* next_mapping = i >= s->mapping.next ? NULL : + array_get(&(s->mapping), i); + + if (next_mapping == NULL || next_mapping->begin > c1) { + int i1 = array_index(&(s->mapping), mapping); + + next_mapping = insert_mapping(s, c1, c1+1); + + if (c1 < c) + i1++; + mapping = array_get(&(s->mapping), i1); + } + + next_mapping->dir_index = mapping->dir_index; + next_mapping->first_mapping_index = + mapping->first_mapping_index < 0 ? + array_index(&(s->mapping), mapping) : + mapping->first_mapping_index; + next_mapping->path = mapping->path; + next_mapping->mode = mapping->mode; + next_mapping->read_only = mapping->read_only; + if (mapping->mode & MODE_DIRECTORY) { + next_mapping->info.dir.parent_mapping_index = + mapping->info.dir.parent_mapping_index; + next_mapping->info.dir.first_dir_index = + mapping->info.dir.first_dir_index + + 0x10 * s->sectors_per_cluster * + (mapping->end - mapping->begin); + } else + next_mapping->info.file.offset = mapping->info.file.offset + + mapping->end - mapping->begin; + + mapping = next_mapping; + } + + cluster = c1; + } + + return 0; +} + +static int commit_direntries(BDRVVVFATState* s, + int dir_index, int parent_mapping_index) +{ + direntry_t* direntry = array_get(&(s->directory), dir_index); + uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry); + mapping_t* mapping = find_mapping_for_cluster(s, first_cluster); + + int factor = 0x10 * s->sectors_per_cluster; + int old_cluster_count, new_cluster_count; + int current_dir_index = mapping->info.dir.first_dir_index; + int first_dir_index = current_dir_index; + int ret, i; + uint32_t c; + + DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index)); + + assert(direntry); + assert(mapping); + assert(mapping->begin == first_cluster); + assert(mapping->info.dir.first_dir_index < s->directory.next); + assert(mapping->mode & MODE_DIRECTORY); + assert(dir_index == 0 || is_directory(direntry)); + + mapping->info.dir.parent_mapping_index = parent_mapping_index; + + if (first_cluster == 0) { + old_cluster_count = new_cluster_count = + s->last_cluster_of_root_directory; + } else { + for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c); + c = fat_get(s, c)) + old_cluster_count++; + + for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c); + c = modified_fat_get(s, c)) + new_cluster_count++; + } + + if (new_cluster_count > old_cluster_count) { + if (insert_direntries(s, + current_dir_index + factor * old_cluster_count, + factor * (new_cluster_count - old_cluster_count)) == NULL) + return -1; + } else if (new_cluster_count < old_cluster_count) + remove_direntries(s, + current_dir_index + factor * new_cluster_count, + factor * (old_cluster_count - new_cluster_count)); + + for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) { + void* direntry = array_get(&(s->directory), current_dir_index); + int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry, + s->sectors_per_cluster); + if (ret) + return ret; + assert(!strncmp((char *) s->directory.pointer, VOLUME_LABEL, strlen(VOLUME_LABEL))); + current_dir_index += factor; + } + + ret = commit_mappings(s, first_cluster, dir_index); + if (ret) + return ret; + + /* recurse */ + for (i = 0; i < factor * new_cluster_count; i++) { + direntry = array_get(&(s->directory), first_dir_index + i); + if (is_directory(direntry) && !is_dot(direntry)) { + mapping = find_mapping_for_cluster(s, first_cluster); + assert(mapping->mode & MODE_DIRECTORY); + ret = commit_direntries(s, first_dir_index + i, + array_index(&(s->mapping), mapping)); + if (ret) + return ret; + } + } + + return 0; +} + +/* commit one file (adjust contents, adjust mapping), + return first_mapping_index */ +static int commit_one_file(BDRVVVFATState* s, + int dir_index, uint32_t offset) +{ + direntry_t* direntry = array_get(&(s->directory), dir_index); + uint32_t c = begin_of_direntry(direntry); + uint32_t first_cluster = c; + mapping_t* mapping = find_mapping_for_cluster(s, c); + uint32_t size = filesize_of_direntry(direntry); + unsigned char* cluster = malloc(s->cluster_size); + uint32_t i; + int fd = 0; + + assert(offset < size); + assert((offset % s->cluster_size) == 0); + + for (i = s->cluster_size; i < offset; i += s->cluster_size) + c = modified_fat_get(s, c); + + fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); + if (fd < 0) { + fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, + strerror(errno), errno); + return fd; + } + if (offset > 0) + if (lseek(fd, offset, SEEK_SET) != offset) + return -3; + + while (offset < size) { + uint32_t c1; + int rest_size = (size - offset > s->cluster_size ? + s->cluster_size : size - offset); + int ret; + + c1 = modified_fat_get(s, c); + + assert((size - offset == 0 && fat_eof(s, c)) || + (size > offset && c >=2 && !fat_eof(s, c))); + assert(size >= 0); + + ret = vvfat_read(s->bs, cluster2sector(s, c), + cluster, (rest_size + 0x1ff) / 0x200); + + if (ret < 0) + return ret; + + if (write(fd, cluster, rest_size) < 0) + return -2; + + offset += rest_size; + c = c1; + } + + ftruncate(fd, size); + close(fd); + + return commit_mappings(s, first_cluster, dir_index); +} + +#ifdef DEBUG +/* test, if all mappings point to valid direntries */ +static void check1(BDRVVVFATState* s, const char *where) +{ + int i; + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { + DLOG(fprintf(stderr, "%s: deleted\n", where); print_mapping(mapping)); + continue; + } + assert(mapping->dir_index >= 0); + assert(mapping->dir_index < s->directory.next); + direntry_t* direntry = array_get(&(s->directory), mapping->dir_index); + assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0); + if (mapping->mode & MODE_DIRECTORY) { + assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next); + assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0); + } + } +} + +/* test, if all direntries have mappings */ +static void check2(BDRVVVFATState* s, const char *where) +{ + int i; + int first_mapping = -1; + + for (i = 0; i < s->directory.next; i++) { + direntry_t* direntry = array_get(&(s->directory), i); + + if (is_short_name(direntry) && begin_of_direntry(direntry)) { + mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry)); + assert(mapping); + assert(mapping->dir_index == i || is_dot(direntry)); + assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry)); + } + + if ((i % (0x10 * s->sectors_per_cluster)) == 0) { + /* cluster start */ + int j, count = 0; + + for (j = 0; j < s->mapping.next; j++) { + mapping_t* mapping = array_get(&(s->mapping), j); + if (mapping->mode & MODE_DELETED) + continue; + if (mapping->mode & MODE_DIRECTORY) { + if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) { + assert(++count == 1); + if (mapping->first_mapping_index == -1) + first_mapping = array_index(&(s->mapping), mapping); + else + assert(first_mapping == mapping->first_mapping_index); + if (mapping->info.dir.parent_mapping_index < 0) + assert(j == 0); + else { + mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index); + assert(parent->mode & MODE_DIRECTORY); + assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index); + } + } + } + } + if (count == 0) + first_mapping = -1; + } + } +} +#endif + +static int handle_renames_and_mkdirs(BDRVVVFATState* s) +{ + int i; + +#ifdef DEBUG + fprintf(stderr, "handle_renames\n"); + for (i = 0; i < s->commits.next; i++) { + commit_t* commit = array_get(&(s->commits), i); + fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action); + } +#endif + + for (i = 0; i < s->commits.next;) { + commit_t* commit = array_get(&(s->commits), i); + if (commit->action == ACTION_RENAME) { + mapping_t* mapping = find_mapping_for_cluster(s, + commit->param.rename.cluster); + char* old_path = mapping->path; + + assert(commit->path); + mapping->path = commit->path; + if (rename(old_path, mapping->path)) + return -2; + + if (mapping->mode & MODE_DIRECTORY) { + int l1 = strlen(mapping->path); + int l2 = strlen(old_path); + int diff = l1 - l2; + direntry_t* direntry = array_get(&(s->directory), + mapping->info.dir.first_dir_index); + uint32_t c = mapping->begin; + int i = 0; + + /* recurse */ + while (!fat_eof(s, c)) { + do { + direntry_t* d = direntry + i; + + if (is_file(d) || (is_directory(d) && !is_dot(d))) { + mapping_t* m = find_mapping_for_cluster(s, + begin_of_direntry(d)); + int l = strlen(m->path); + char* new_path = malloc(l + diff + 1); + + assert(!strncmp(m->path, mapping->path, l2)); + + strcpy(new_path, mapping->path); + strcpy(new_path + l1, m->path + l2); + + schedule_rename(s, m->begin, new_path); + } + i++; + } while((i % (0x10 * s->sectors_per_cluster)) != 0); + c = fat_get(s, c); + } + } + + free(old_path); + array_remove(&(s->commits), i); + continue; + } else if (commit->action == ACTION_MKDIR) { + mapping_t* mapping; + int j, parent_path_len; + +#ifdef __MINGW32__ + if (mkdir(commit->path)) + return -5; +#else + if (mkdir(commit->path, 0755)) + return -5; +#endif + + mapping = insert_mapping(s, commit->param.mkdir.cluster, + commit->param.mkdir.cluster + 1); + if (mapping == NULL) + return -6; + + mapping->mode = MODE_DIRECTORY; + mapping->read_only = 0; + mapping->path = commit->path; + j = s->directory.next; + assert(j); + insert_direntries(s, s->directory.next, + 0x10 * s->sectors_per_cluster); + mapping->info.dir.first_dir_index = j; + + parent_path_len = strlen(commit->path) + - strlen(get_basename(commit->path)) - 1; + for (j = 0; j < s->mapping.next; j++) { + mapping_t* m = array_get(&(s->mapping), j); + if (m->first_mapping_index < 0 && m != mapping && + !strncmp(m->path, mapping->path, parent_path_len) && + strlen(m->path) == parent_path_len) + break; + } + assert(j < s->mapping.next); + mapping->info.dir.parent_mapping_index = j; + + array_remove(&(s->commits), i); + continue; + } + + i++; + } + return 0; +} + +/* + * TODO: make sure that the short name is not matching *another* file + */ +static int handle_commits(BDRVVVFATState* s) +{ + int i, fail = 0; + + vvfat_close_current_file(s); + + for (i = 0; !fail && i < s->commits.next; i++) { + commit_t* commit = array_get(&(s->commits), i); + switch(commit->action) { + case ACTION_RENAME: case ACTION_MKDIR: + assert(0); + fail = -2; + break; + case ACTION_WRITEOUT: { + direntry_t* entry = array_get(&(s->directory), + commit->param.writeout.dir_index); + uint32_t begin = begin_of_direntry(entry); + mapping_t* mapping = find_mapping_for_cluster(s, begin); + + assert(mapping); + assert(mapping->begin == begin); + assert(commit->path == NULL); + + if (commit_one_file(s, commit->param.writeout.dir_index, + commit->param.writeout.modified_offset)) + fail = -3; + + break; + } + case ACTION_NEW_FILE: { + int begin = commit->param.new_file.first_cluster; + mapping_t* mapping = find_mapping_for_cluster(s, begin); + direntry_t* entry; + int i; + + /* find direntry */ + for (i = 0; i < s->directory.next; i++) { + entry = array_get(&(s->directory), i); + if (is_file(entry) && begin_of_direntry(entry) == begin) + break; + } + + if (i >= s->directory.next) { + fail = -6; + continue; + } + + /* make sure there exists an initial mapping */ + if (mapping && mapping->begin != begin) { + mapping->end = begin; + mapping = NULL; + } + if (mapping == NULL) { + mapping = insert_mapping(s, begin, begin+1); + } + /* most members will be fixed in commit_mappings() */ + assert(commit->path); + mapping->path = commit->path; + mapping->read_only = 0; + mapping->mode = MODE_NORMAL; + mapping->info.file.offset = 0; + + if (commit_one_file(s, i, 0)) + fail = -7; + + break; + } + default: + assert(0); + } + } + if (i > 0 && array_remove_slice(&(s->commits), 0, i)) + return -1; + return fail; +} + +static int handle_deletes(BDRVVVFATState* s) +{ + int i, deferred = 1, deleted = 1; + + /* delete files corresponding to mappings marked as deleted */ + /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */ + while (deferred && deleted) { + deferred = 0; + deleted = 0; + + for (i = 1; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { + direntry_t* entry = array_get(&(s->directory), + mapping->dir_index); + + DLOG(fprintf(stderr, "%s:%u: ", __FUNCTION__, __LINE__); print_mapping(mapping); print_direntry(entry)); + + if (is_free(entry)) { + /* remove file/directory */ + if (mapping->mode & MODE_DIRECTORY) { + int j, next_dir_index = s->directory.next, + first_dir_index = mapping->info.dir.first_dir_index; + + if (rmdir(mapping->path) < 0) { + if (errno == ENOTEMPTY) { + deferred++; + continue; + } else + return -5; + } + + for (j = 1; j < s->mapping.next; j++) { + mapping_t* m = array_get(&(s->mapping), j); + if (m->mode & MODE_DIRECTORY && + m->info.dir.first_dir_index > + first_dir_index && + m->info.dir.first_dir_index < + next_dir_index) + next_dir_index = + m->info.dir.first_dir_index; + } + remove_direntries(s, first_dir_index, + next_dir_index - first_dir_index); + + deleted++; + } else { + if (unlink(mapping->path)) + return -4; + deleted++; + } + + DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); + remove_mapping(s, i); + } + } + } + } + + return 0; +} + +static int have_deletes(BDRVVVFATState* s) +{ + int i; + + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { + return 1; + } + } + + return 0; +} + +/* + * synchronize mapping with new state: + * + * - copy FAT (with bdrv_read) + * - mark all filenames corresponding to mappings as deleted + * - recurse direntries from root (using bs->bdrv_read) + * - delete files corresponding to mappings marked as deleted + */ +static int do_commit(BDRVVVFATState* s) +{ + int ret = 0; + + /* the real meat are the commits. Nothing to do? Move along! */ + if ((0 == s->commits.next) && (0 == have_deletes(s))) { + DLOG(fprintf(stderr, "%s:%u: nothing to do\n", __FUNCTION__, __LINE__)); + return 0; + } + + vvfat_close_current_file(s); + + ret = handle_renames_and_mkdirs(s); + if (ret) { + fprintf(stderr, "Error handling renames (%d)\n", ret); + assert(0); + return ret; + } + + /* copy FAT (with bdrv_read) */ + memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat); + + /* recurse direntries from root (using bs->bdrv_read) */ + ret = commit_direntries(s, 0, -1); + if (ret) { + fprintf(stderr, "Fatal: error while committing (%d)\n", ret); + assert(0); + return ret; + } + + ret = handle_commits(s); + if (ret) { + fprintf(stderr, "Error handling commits (%d)\n", ret); + assert(0); + return ret; + } + + ret = handle_deletes(s); + if (ret) { + fprintf(stderr, "Error deleting\n"); + assert(0); + return ret; + } + + s->qcow->drv->bdrv_make_empty(s->qcow); + + memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); + +DLOG(checkpoint(__FUNCTION__)); + return 0; +} + +static int try_commit(BDRVVVFATState* s) +{ + vvfat_close_current_file(s); + +DLOG(checkpoint(__FUNCTION__)); + + if(!is_consistent(s)) + return -1; + + return do_commit(s); +} + +static void +vvfat_write_timer(void *opaque) +{ + BDRVVVFATState *s = opaque; + + DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); + +DLOG(checkpoint("vvfat_write_timer: before try_commits")); + + try_commit(s); + +DLOG(checkpoint("vvfat_write_timer: after try_commits")); +} + +static int vvfat_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVVVFATState *s = bs->opaque; + mapping_t* mapping; +#ifdef DEBUG_SECTORS + int32_t orig_sector = sector_num; +#endif + int64_t start_cluster, end_cluster; + int i, ret; + +DLOG(checkpoint(__FUNCTION__)); + + vvfat_close_current_file(s); + + /* + * Some sanity checks: + * - do not allow writing to the boot sector + * - do not allow to write non-ASCII filenames + */ + + if (sector_num < s->first_sectors_number) { + DLOG(fprintf(stderr, "%s:%u: sector: %u nb %u (first: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->first_sectors_number)); + return -1; + } + +#ifdef DEBUG_SECTORS + for (i = 0; i < nb_sectors; i++) { + fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); + hexdump(buf + i * 0x200, 0x200); + } +#endif + + DLOG(fprintf(stderr, "%s:%u: check mappings, sector: %u nb %u (faked: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->faked_sectors)); + + if (sector_num >= s->faked_sectors) { + start_cluster = sector2cluster(s, sector_num); + } else { + start_cluster = 0; + } + if (sector_num + nb_sectors - 1 >= s->faked_sectors) { + end_cluster = sector2cluster(s, sector_num + nb_sectors - 1); + } else { + end_cluster = -1; + } + + for (i = start_cluster; i <= end_cluster; ) { + DLOG(fprintf(stderr, "%s:%u: cluster %u\n", __FUNCTION__, __LINE__, i)); + mapping = find_mapping_for_cluster(s, i); + DLOG(fprintf(stderr, "%s:%u: mapping %p\n", __FUNCTION__, __LINE__, mapping)); + if (mapping) { + if (mapping->read_only) { + fprintf(stderr, "Tried to write to write-protected file %s\n", + mapping->path); + return -1; + } + + if (mapping->mode & MODE_DIRECTORY) { + int begin = cluster2sector(s, i); + int end = begin + s->sectors_per_cluster, k; + int dir_index; + const direntry_t* direntries; + long_file_name lfn; + + lfn_init(&lfn); + + if (begin < sector_num) + begin = sector_num; + if (end > sector_num + nb_sectors) + end = sector_num + nb_sectors; + dir_index = mapping->dir_index + + 0x10 * (begin - mapping->begin * s->sectors_per_cluster); + direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); + + for (k = 0; k < (end - begin) * 0x10; k++) { + /* do not allow non-ASCII filenames */ + if (parse_long_name(&lfn, direntries + k) < 0) { + fprintf(stderr, "Warning: non-ASCII filename\n"); + return -1; + } + /* no access to the direntry of a read-only file */ + else if (is_short_name(direntries+k) && + (direntries[k].attributes & 1)) { + if (memcmp(direntries + k, + array_get(&(s->directory), dir_index + k), + sizeof(direntry_t))) { + fprintf(stderr, "Warning: tried to write to write-protected file\n"); + return -1; + } + } + } + } + i = mapping->end; + } else { + i++; + } + } + + /* + * Use qcow backend. Commit later. + */ + DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); + ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors); + if (ret < 0) { + fprintf(stderr, "Error writing to qcow backend\n"); + return ret; + } + + for (i = start_cluster; i <= end_cluster; i++) + s->used_clusters[i] |= USED_ALLOCATED; + + qemu_mod_timer(s->write_timer, qemu_get_clock(rt_clock) + ticks_per_sec); + return 0; +} + +static int vvfat_is_allocated(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, int* n) +{ + BDRVVVFATState* s = bs->opaque; + *n = s->sector_count - sector_num; + if (*n > nb_sectors) + *n = nb_sectors; + else if (*n < 0) + return 0; + return 1; +} + +static int enable_write(BDRVVVFATState *s) +{ + int error; + int size; + + DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); + + size = sector2cluster(s, s->sector_count); + s->used_clusters = calloc(size, 1); + + array_init(&(s->commits), sizeof(commit_t)); + + s->qcow_filename = malloc(1024); + get_tmp_filename(s->qcow_filename, 1024); + error = bdrv_create(&bdrv_qcow, s->qcow_filename, s->sector_count, "", 0); + if (error < 0) { + DLOG(fprintf(stderr, "%s:%u: bdrv_create '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); + return -1; + } + + s->qcow = bdrv_new(""); + if (s->qcow == NULL) { + DLOG(fprintf(stderr, "%s:%u: bdrv_new: Out of memory\n", __FUNCTION__, __LINE__)); +#ifndef _WIN32 + unlink(s->qcow_filename); +#endif + return -1; + } + + error = bdrv_open(s->qcow, s->qcow_filename, 0); + if (error < 0) { + DLOG(fprintf(stderr, "%s:%u: bdrv_open '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); +#ifndef _WIN32 + unlink(s->qcow_filename); +#endif + bdrv_delete(s->qcow); + return -1; + } + + s->write_timer = qemu_new_timer(rt_clock, vvfat_write_timer, s); + if (NULL == s->write_timer) { + DLOG(fprintf(stderr, "%s:%u: write_timer: Out of memory\n", __FUNCTION__, __LINE__)); +#ifndef _WIN32 + unlink(s->qcow_filename); +#endif + bdrv_delete(s->qcow); + return -1; + } + + s->qcow->is_temporary = 1; + +#ifndef _WIN32 + unlink(s->qcow_filename); +#endif + + DLOG(fprintf(stderr, "%s:%u: write enabled\n", __FUNCTION__, __LINE__)); + return 0; +} + +static void vvfat_close(BlockDriverState *bs) +{ + BDRVVVFATState *s = bs->opaque; + + if (qemu_timer_pending(s->write_timer)) { + qemu_del_timer(s->write_timer); + vvfat_write_timer(s); + } + + vvfat_close_current_file(s); + + if (s->qcow) { + qemu_free(s->qcow_filename); + + bdrv_delete(s->qcow); + s->qcow = NULL; + } + + array_free(&(s->fat)); + array_free(&(s->directory)); + array_free(&(s->mapping)); + + if(s->cluster_buffer) + free(s->cluster_buffer); +} + +BlockDriver bdrv_vvfat = { + "vvfat", + sizeof(BDRVVVFATState), + NULL, /* no probe for protocols */ + vvfat_open, + vvfat_read, + vvfat_write, + vvfat_close, + NULL, /* ??? Not sure if we can do any meaningful flushing. */ + NULL, + vvfat_is_allocated, + .protocol_name = "fat", +}; + +#ifdef DEBUG +static void +checkpoint(const char *where) +{ + DLOG(fprintf(stderr, "%s:%u: checkpoint(%s)\n", __FUNCTION__, __LINE__, where)); + + assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); + DLOG(fprintf(stderr, "checkpoint(%s): call check1()\n", where)); + check1(vvv, where); + DLOG(fprintf(stderr, "checkpoint(%s): call check2()\n", where)); + check2(vvv, where); + assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); +#if 0 + if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf) + fprintf(stderr, "Nonono!\n"); + mapping_t* mapping; + direntry_t* direntry; + assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next); + assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next); + if (vvv->mapping.next<47) + return; + assert((mapping = array_get(&(vvv->mapping), 47))); + assert(mapping->dir_index < vvv->directory.next); + direntry = array_get(&(vvv->directory), mapping->dir_index); + assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0); +#endif + DLOG(fprintf(stderr, "checkpoint(%s): done\n", where)); + return; + /* avoid compiler warnings: */ + hexdump(NULL, 100); + remove_mapping(vvv, 0); + print_mapping(NULL); + print_direntry(NULL); +} +#endif + diff --git a/block.c b/block.c new file mode 100644 index 0000000..4d5a7cf --- /dev/null +++ b/block.c @@ -0,0 +1,631 @@ +/* $Id: block.c,v 1.1 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#ifndef QEMU_OLD +#include "qemu-common.h" +#endif +#include +#ifndef QEMU_OLD +#include "block_int.h" +#endif + +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) + +static BlockDriverState *bdrv_first; +static BlockDriver *first_drv; + +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif + +static void bdrv_close(BlockDriverState *bs); + +static int +path_is_absolute(const char *path) +{ + const char *p; +#ifdef _WIN32 + /* specific case for names like: "\\.\d:" */ + if (*path == '/' || *path == '\\') + return 1; +#endif + p = strchr(path, ':'); + if (p) + p++; + else + p = path; +#ifdef _WIN32 + return (*p == '/' || *p == '\\'); +#else + return (*p == '/'); +#endif +} + +/* if filename is absolute, just copy it to dest. Otherwise, build a + path to it by considering it is relative to base_path. URL are + supported. */ +static void +path_combine(char *dest, int dest_size, + const char *base_path, + const char *filename) +{ + const char *p, *p1; + int len; + + if (dest_size <= 0) + return; + if (path_is_absolute(filename)) { + pstrcpy(dest, dest_size, filename); + } else { + p = strchr(base_path, ':'); + if (p) + p++; + else + p = base_path; + p1 = strrchr(base_path, '/'); +#ifdef _WIN32 + { + const char *p2; + p2 = strrchr(base_path, '\\'); + if (!p1 || p2 > p1) + p1 = p2; + } +#endif + if (p1) + p1++; + else + p1 = base_path; + if (p1 > p) + p = p1; + len = p - base_path; + if (len > dest_size - 1) + len = dest_size - 1; + memcpy(dest, base_path, len); + dest[len] = '\0'; + pstrcat(dest, dest_size, filename); + } +} + +#ifdef _WIN32 +void get_tmp_filename(char *filename, int size) +{ + char temp_dir[MAX_PATH]; + + GetTempPath(MAX_PATH, temp_dir); + GetTempFileName(temp_dir, "x49", 0, filename); +} +#else +void get_tmp_filename(char *filename, int size) +{ + int fd; + + /* XXX: race condition possible */ + pstrcpy(filename, size, "/tmp/x49gp.XXXXXX"); + fd = mkstemp(filename); + close(fd); +} +#endif + +#ifdef _WIN32 +static int is_windows_drive_prefix(const char *filename) +{ + return (((filename[0] >= 'a' && filename[0] <= 'z') || + (filename[0] >= 'A' && filename[0] <= 'Z')) && + filename[1] == ':'); +} + +static int is_windows_drive(const char *filename) +{ + if (is_windows_drive_prefix(filename) && + filename[2] == '\0') + return 1; + if (strstart(filename, "\\\\.\\", NULL) || + strstart(filename, "//./", NULL)) + return 1; + return 0; +} +#endif + +static BlockDriver * +find_protocol(const char *filename) +{ + BlockDriver *drv1; + char protocol[128]; + int len; + const char *p; + +#ifdef _WIN32 + if (is_windows_drive(filename) || + is_windows_drive_prefix(filename)) + return &bdrv_raw; +#endif + p = strchr(filename, ':'); + if (!p) + return &bdrv_raw; + len = p - filename; + if (len > sizeof(protocol) - 1) + len = sizeof(protocol) - 1; + memcpy(protocol, filename, len); + protocol[len] = '\0'; + for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { +fprintf(stderr, "%s:%u: protocol '%s', drv->protocol_name '%s'\n", __FUNCTION__, __LINE__, protocol, drv1->protocol_name); + if (drv1->protocol_name && + !strcmp(drv1->protocol_name, protocol)) { +fprintf(stderr, "%s:%u: protocol '%s', drv %p\n", __FUNCTION__, __LINE__, protocol, drv1); + return drv1; + } + } +fprintf(stderr, "%s:%u: protocol '%s', NULL\n", __FUNCTION__, __LINE__, protocol); + return NULL; +} + +/* XXX: force raw format if block or character device ? It would + simplify the BSD case */ +static BlockDriver * +find_image_format(const char *filename) +{ + int ret, score, score_max; + BlockDriver *drv1, *drv; + uint8_t buf[2048]; + BlockDriverState *bs; + + drv = find_protocol(filename); + /* no need to test disk image formats for vvfat */ + if (drv == &bdrv_vvfat) + return drv; + + ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); + if (ret < 0) + return NULL; + ret = bdrv_pread(bs, 0, buf, sizeof(buf)); + bdrv_delete(bs); + if (ret < 0) { + return NULL; + } + + score_max = 0; + for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { + if (drv1->bdrv_probe) { + score = drv1->bdrv_probe(buf, ret, filename); + if (score > score_max) { + score_max = score; + drv = drv1; + } + } + } + return drv; +} + +int +bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags) +{ + if (!drv->bdrv_create) + return -ENOTSUP; + return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); +} + +static void +bdrv_register(BlockDriver *bdrv) +{ + bdrv->next = first_drv; + first_drv = bdrv; +} + +/* create a new block device (by default it is empty) */ +BlockDriverState * +bdrv_new(const char *device_name) +{ + BlockDriverState **pbs, *bs; + + bs = qemu_mallocz(sizeof(BlockDriverState)); + if(!bs) + return NULL; + pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); + if (device_name[0] != '\0') { + /* insert at the end */ + pbs = &bdrv_first; + while (*pbs != NULL) + pbs = &(*pbs)->next; + *pbs = bs; + } + return bs; +} + +/** + * Truncate file to 'offset' bytes (needed only for file protocols) + */ +int +bdrv_truncate(BlockDriverState *bs, int64_t offset) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_truncate) + return -ENOTSUP; + return drv->bdrv_truncate(bs, offset); +} + +/** + * Length of a file in bytes. Return < 0 if error or unknown. + */ +int64_t +bdrv_getlength(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_getlength) { + /* legacy mode */ + return bs->total_sectors * SECTOR_SIZE; + } + return drv->bdrv_getlength(bs); +} + +int +bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) +{ + BlockDriverState *bs; + int ret; + +fprintf(stderr, "%s:%u: filename '%s'\n", __FUNCTION__, __LINE__, filename); + + bs = bdrv_new(""); + if (!bs) + return -ENOMEM; + ret = bdrv_open(bs, filename, flags | BDRV_O_FILE); + if (ret < 0) { + bdrv_delete(bs); +fprintf(stderr, "%s:%u: '%s': %d\n", __FUNCTION__, __LINE__, filename, ret); + return ret; + } + *pbs = bs; +fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__); + return 0; +} + +int +bdrv_open(BlockDriverState *bs, const char *filename, int flags) +{ + int ret, open_flags; + char backing_filename[1024]; + BlockDriver *drv = NULL; + +fprintf(stderr, "%s:%u: filename '%s'\n", __FUNCTION__, __LINE__, filename); + + bs->read_only = 0; + bs->is_temporary = 0; + bs->encrypted = 0; + + pstrcpy(bs->filename, sizeof(bs->filename), filename); + if (flags & BDRV_O_FILE) { + drv = find_protocol(filename); + if (!drv) { +fprintf(stderr, "%s:%u: drv: %p\n", __FUNCTION__, __LINE__, drv); + return -ENOENT; + } + } else { + if (!drv) { + drv = find_image_format(filename); + if (!drv) { +fprintf(stderr, "%s:%u: drv: %p\n", __FUNCTION__, __LINE__, drv); + return -1; + } + } + } + +fprintf(stderr, "%s:%u: drv: %p\n", __FUNCTION__, __LINE__, drv); + bs->drv = drv; + bs->opaque = qemu_mallocz(drv->instance_size); + if (bs->opaque == NULL && drv->instance_size > 0) { +fprintf(stderr, "%s:%u: no opaque\n", __FUNCTION__, __LINE__); + return -1; + } + /* Note: for compatibility, we open disk image files as RDWR, and + RDONLY as fallback */ + if (!(flags & BDRV_O_FILE)) + open_flags = BDRV_O_RDWR; + else + open_flags = flags & ~(BDRV_O_FILE); + ret = drv->bdrv_open(bs, filename, open_flags); +fprintf(stderr, "%s:%u: drv->bdrv_open: %d\n", __FUNCTION__, __LINE__, ret); + if (ret == -EACCES && !(flags & BDRV_O_FILE)) { + ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY); + bs->read_only = 1; + } + if (ret < 0) { + qemu_free(bs->opaque); + bs->opaque = NULL; + bs->drv = NULL; +fprintf(stderr, "%s:%u: return %d\n", __FUNCTION__, __LINE__, ret); + return ret; + } + if (drv->bdrv_getlength) { + bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + } +#ifndef _WIN32 + if (bs->is_temporary) { + unlink(filename); + } +#endif + if (bs->backing_file[0] != '\0') { + /* if there is a backing file, use it */ + bs->backing_hd = bdrv_new(""); + if (!bs->backing_hd) { + fail: + bdrv_close(bs); +fprintf(stderr, "%s:%u: return -ENOMEM\n", __FUNCTION__, __LINE__); + return -ENOMEM; + } +fprintf(stderr, "%s:%u: combine '%s' '%s'\n", __FUNCTION__, __LINE__, filename, bs->backing_file); + path_combine(backing_filename, sizeof(backing_filename), + filename, bs->backing_file); +fprintf(stderr, "%s:%u: combine: '%s'\n", __FUNCTION__, __LINE__, backing_filename); + if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0) { +fprintf(stderr, "%s:%u: backing fail\n", __FUNCTION__, __LINE__); + goto fail; + } + } + + /* call the change callback */ + bs->media_changed = 1; + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + +fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__); + return 0; +} + +static void +bdrv_close(BlockDriverState *bs) +{ + if (NULL == bs->drv) + return; + + /* call the change callback */ + bs->media_changed = 1; + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + + if (bs->backing_hd) + bdrv_delete(bs->backing_hd); + + bs->drv->bdrv_close(bs); + +#ifdef _WIN32 + if (bs->is_temporary) { + unlink(bs->filename); + } +#endif + + qemu_free(bs->opaque); + bs->opaque = NULL; + bs->drv = NULL; +} + +void +bdrv_delete(BlockDriverState *bs) +{ + /* XXX: remove the driver list */ + bdrv_close(bs); + qemu_free(bs); +} + +/* return < 0 if error. See bdrv_write() for the return codes */ +int +bdrv_read(BlockDriverState * bs, int64_t sector_num, + uint8_t * buf, int nb_sectors) +{ + BlockDriver *drv = bs->drv; + + if (!drv) + return -ENOMEDIUM; + + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(buf, bs->boot_sector_data, 512); + sector_num++; + nb_sectors--; + buf += 512; + if (nb_sectors == 0) + return 0; + } + if (drv->bdrv_pread) { + int ret, len; + + len = nb_sectors * 512; + ret = drv->bdrv_pread(bs, sector_num * 512, buf, len); + if (ret < 0) + return ret; + else if (ret != len) + return -EINVAL; + else + return 0; + } else { + return drv->bdrv_read(bs, sector_num, buf, nb_sectors); + } +} + +/* Return < 0 if error. Important errors are: + -EIO generic I/O error (may happen for all errors) + -ENOMEDIUM No media inserted. + -EINVAL Invalid sector number or nb_sectors + -EACCES Trying to write a read-only device +*/ +static int +bdrv_write(BlockDriverState * bs, int64_t sector_num, + const uint8_t * buf, int nb_sectors) +{ + BlockDriver *drv = bs->drv; + + if (!bs->drv) + return -ENOMEDIUM; + if (bs->read_only) + return -EACCES; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); + } + if (drv->bdrv_pwrite) { + int ret, len; + + len = nb_sectors * 512; + ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len); + if (ret < 0) + return ret; + else if (ret != len) + return -EIO; + else + return 0; + } else { + return drv->bdrv_write(bs, sector_num, buf, nb_sectors); + } +} + +static int +bdrv_pread_em(BlockDriverState * bs, int64_t offset, uint8_t * buf, int count1) +{ + uint8_t tmp_buf[SECTOR_SIZE]; + int len, nb_sectors, count; + int64_t sector_num; + + count = count1; + /* first read to align to sector start */ + len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); + if (len > count) + len = count; + sector_num = offset >> SECTOR_BITS; + if (len > 0) { + if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len); + count -= len; + if (count == 0) + return count1; + sector_num++; + buf += len; + } + + /* read the sectors "in place" */ + nb_sectors = count >> SECTOR_BITS; + if (nb_sectors > 0) { + if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0) + return -EIO; + sector_num += nb_sectors; + len = nb_sectors << SECTOR_BITS; + buf += len; + count -= len; + } + + /* add data from the last sector */ + if (count > 0) { + if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + memcpy(buf, tmp_buf, count); + } + return count1; +} + +static int +bdrv_pwrite_em(BlockDriverState * bs, int64_t offset, + const uint8_t * buf, int count1) +{ + uint8_t tmp_buf[SECTOR_SIZE]; + int len, nb_sectors, count; + int64_t sector_num; + + count = count1; + /* first write to align to sector start */ + len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); + if (len > count) + len = count; + sector_num = offset >> SECTOR_BITS; + if (len > 0) { + if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len); + if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + count -= len; + if (count == 0) + return count1; + sector_num++; + buf += len; + } + + /* write the sectors "in place" */ + nb_sectors = count >> SECTOR_BITS; + if (nb_sectors > 0) { + if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0) + return -EIO; + sector_num += nb_sectors; + len = nb_sectors << SECTOR_BITS; + buf += len; + count -= len; + } + + /* add data from the last sector */ + if (count > 0) { + if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + memcpy(tmp_buf, buf, count); + if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) + return -EIO; + } + return count1; +} + +/** + * Read with byte offsets (needed only for file protocols) + */ +int +bdrv_pread(BlockDriverState * bs, int64_t offset, void *buf1, int count1) +{ + BlockDriver *drv = bs->drv; + + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_pread) + return bdrv_pread_em(bs, offset, buf1, count1); + return drv->bdrv_pread(bs, offset, buf1, count1); +} + +/** + * Write with byte offsets (needed only for file protocols) + */ +int +bdrv_pwrite(BlockDriverState * bs, int64_t offset, const void *buf1, int count1) +{ + BlockDriver *drv = bs->drv; + + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_pwrite) + return bdrv_pwrite_em(bs, offset, buf1, count1); + return drv->bdrv_pwrite(bs, offset, buf1, count1); +} + +void +bdrv_flush(BlockDriverState *bs) +{ + if (bs->drv->bdrv_flush) + bs->drv->bdrv_flush(bs); + if (bs->backing_hd) + bdrv_flush(bs->backing_hd); +} + +void +bdrv_init(void) +{ + /* bdrv_register(&bdrv_raw); */ + /* bdrv_register(&bdrv_host_device); */ + bdrv_register(&bdrv_qcow); + bdrv_register(&bdrv_vvfat); +} diff --git a/boot-49g+.bin b/boot-49g+.bin new file mode 100644 index 0000000..2aa6736 Binary files /dev/null and b/boot-49g+.bin differ diff --git a/boot-50g.bin b/boot-50g.bin new file mode 100644 index 0000000..674556e Binary files /dev/null and b/boot-50g.bin differ diff --git a/boot.bin b/boot.bin new file mode 100644 index 0000000..02659be Binary files /dev/null and b/boot.bin differ diff --git a/config.tmpl b/config.tmpl new file mode 100644 index 0000000..d7ac773 --- /dev/null +++ b/config.tmpl @@ -0,0 +1,13 @@ +[x49gp] +basename= +[gui] +name=hp50g +image=hp50g.png +[flash] +filename=flash-50g +[sram] +filename=sram +[s3c2410-sram] +filename=s3c2410-sram +[s3c2410-sdi] +filename=sdcard.dmg diff --git a/flash.c b/flash.c new file mode 100644 index 0000000..f13fac4 --- /dev/null +++ b/flash.c @@ -0,0 +1,639 @@ +/* $Id: flash.c,v 1.18 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define FLASH_STATE_NORMAL 0 + +#define FLASH_STATE_UNLOCK1 1 +#define FLASH_STATE_UNLOCK2 2 + +#define FLASH_STATE_ERASE1 3 +#define FLASH_STATE_ERASE2 4 +#define FLASH_STATE_ERASE3 5 + +#define FLASH_STATE_SOFTWARE_EXIT1 6 +#define FLASH_STATE_SOFTWARE_EXIT2 7 +#define FLASH_STATE_CFI_QUERY_EXIT1 8 +#define FLASH_STATE_CFI_QUERY_EXIT2 9 + +#define FLASH_STATE_SOFTWARE_ID 10 +#define FLASH_STATE_CFI_QUERY 11 +#define FLASH_STATE_WORD_PROG 12 + +typedef struct { + void *data; + int state; + unsigned short vendor_ID; + unsigned short device_ID; + const unsigned short *cfi_data; + uint32_t cfi_size; + uint32_t sector_size; + uint32_t block_size; + int fd; + size_t size; + + uint32_t iotype; + uint32_t offset; +} x49gp_flash_t; + +#define SST29VF160_VENDOR_ID 0x00bf +#define SST29VF160_DEVICE_ID 0x2782 + +#define SST29VF160_SECTOR_SIZE 0x00001000 +#define SST29VF160_BLOCK_SIZE 0x00010000 +#define SST29VF160_SIZE 0x00200000 + +static const unsigned short sst29vf160_cfi_data[] = +{ + [0x10] = 0x0051, + [0x11] = 0x0052, + [0x12] = 0x0059, + [0x13] = 0x0001, + [0x14] = 0x0007, + [0x15] = 0x0000, + [0x16] = 0x0000, + [0x17] = 0x0000, + [0x18] = 0x0000, + [0x19] = 0x0000, + [0x1a] = 0x0000, + + [0x1b] = 0x0027, + [0x1c] = 0x0036, + [0x1d] = 0x0000, + [0x1e] = 0x0000, + [0x1f] = 0x0004, + [0x20] = 0x0000, + [0x21] = 0x0004, + [0x23] = 0x0006, + [0x23] = 0x0001, + [0x24] = 0x0000, + [0x25] = 0x0001, + [0x26] = 0x0001, + + [0x27] = 0x0015, + [0x28] = 0x0001, + [0x29] = 0x0000, + [0x2a] = 0x0000, + [0x2b] = 0x0000, + [0x2c] = 0x0002, + [0x2d] = 0x00ff, + [0x2e] = 0x0001, + [0x2f] = 0x0010, + [0x30] = 0x0000, + [0x31] = 0x003f, + [0x32] = 0x0000, + [0x33] = 0x0000, + [0x34] = 0x0001 +}; +#define SST29VF160_CFI_SIZE (sizeof(sst29vf160_cfi_data) / sizeof(sst29vf160_cfi_data[0])) + +static void +flash_state_reset(x49gp_flash_t *flash) +{ + if (flash->state != FLASH_STATE_NORMAL) { + cpu_register_physical_memory(0x00000000, SST29VF160_SIZE, + flash->offset | flash->iotype | IO_MEM_ROMD); + flash->state = FLASH_STATE_NORMAL; + } +} + +static uint32_t +flash_get_halfword(x49gp_flash_t *flash, uint32_t offset) +{ + uint8_t *datap = flash->data; + uint16_t data; + + switch (flash->state) { + default: + flash_state_reset(flash); + /* fall through */ + + case FLASH_STATE_NORMAL: + data = lduw_p(datap + offset); + break; + + case FLASH_STATE_SOFTWARE_ID: + if (offset & 2) { + data = flash->device_ID; + } else { + data = flash->vendor_ID; + } + break; + + case FLASH_STATE_CFI_QUERY: + if (offset < flash->cfi_size) { + data = flash->cfi_data[offset >> 1]; + } else { + data = 0x0000; + } + break; + } + + return data; +} + +static void +flash_put_halfword(x49gp_flash_t *flash, uint32_t offset, uint32_t data) +{ + uint8_t *datap = flash->data; + uint16_t temp; + + data &= 0xffff; + + switch (flash->state) { + default: + flash_state_reset(flash); + /* fall through */ + + case FLASH_STATE_NORMAL: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xaa)) { + flash->state = FLASH_STATE_UNLOCK1; + cpu_register_physical_memory(0x00000000, SST29VF160_SIZE, flash->iotype); + } + break; + + case FLASH_STATE_UNLOCK1: + if (((offset >> 1) == 0x2aaa) && ((data & 0xff) == 0x55)) { + flash->state = FLASH_STATE_UNLOCK2; + } else { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_UNLOCK2: + if ((offset >> 1) == 0x5555) { + switch (data & 0xff) { + case 0xa0: + flash->state = FLASH_STATE_WORD_PROG; + break; + case 0x80: + flash->state = FLASH_STATE_ERASE1; + break; + case 0x90: + flash->state = FLASH_STATE_SOFTWARE_ID; + break; + case 0x98: + flash->state = FLASH_STATE_CFI_QUERY; + break; + default: + flash_state_reset(flash); + break; + } + } else { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_ERASE1: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xaa)) { + flash->state = FLASH_STATE_ERASE2; + } else { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_ERASE2: + if (((offset >> 1) == 0x2aaa) && ((data & 0xff) == 0x55)) { + flash->state = FLASH_STATE_ERASE3; + } else { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_SOFTWARE_EXIT1: + if (((offset >> 1) == 0x2aaa) && ((data & 0xff) == 0x55)) { + flash->state = FLASH_STATE_SOFTWARE_EXIT2; + } else { + flash->state = FLASH_STATE_SOFTWARE_ID; + } + break; + + case FLASH_STATE_SOFTWARE_EXIT2: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xf0)) { + flash_state_reset(flash); + } else { + flash->state = FLASH_STATE_SOFTWARE_ID; + } + break; + + case FLASH_STATE_CFI_QUERY_EXIT1: + if (((offset >> 1) == 0x2aaa) && ((data & 0xff) == 0x55)) { + flash->state = FLASH_STATE_CFI_QUERY_EXIT2; + } else { + flash->state = FLASH_STATE_CFI_QUERY; + } + break; + + case FLASH_STATE_CFI_QUERY_EXIT2: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xf0)) { + flash_state_reset(flash); + } else { + flash->state = FLASH_STATE_CFI_QUERY; + } + break; + + case FLASH_STATE_SOFTWARE_ID: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xaa)) { + flash->state = FLASH_STATE_SOFTWARE_EXIT1; + } else if ((data & 0xff) == 0xf0) { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_CFI_QUERY: + if (((offset >> 1) == 0x5555) && ((data & 0xff) == 0xaa)) { + flash->state = FLASH_STATE_CFI_QUERY_EXIT1; + } else if ((data & 0xff) == 0xf0) { + flash_state_reset(flash); + } + break; + + case FLASH_STATE_WORD_PROG: + temp = lduw_p(datap + offset); + stw_p(datap + offset, data & temp); + +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("write FLASH 2 (state %u) at offset %08x: %04x, result: %04x\n", + flash->state, offset, data, lduw_p(datap + offset)); +#endif + + flash_state_reset(flash); + break; + + case FLASH_STATE_ERASE3: + switch (data & 0xff) { + case 0x10: /* Chip Erase */ +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("erase FLASH %08x %08x\n", 0, SST29VF160_SIZE); +#endif + memset(datap, 0xff, SST29VF160_SIZE); + break; + + case 0x30: /* Sector Erase */ +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("erase FLASH %08x %08x\n", + (offset & ~(flash->sector_size - 1)), + flash->sector_size); +#endif + memset(datap + (offset & ~(flash->sector_size - 1)), 0xff, flash->sector_size); + +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("erase FLASH %08x: %04x, %08x: %04x, %08x: %04x\n", + offset, lduw_p(datap + offset), + offset + 0x800, lduw_p(datap + offset + 0x800), + offset + 0xffc, lduw_p(datap + offset + 0xffc)); +#endif + break; + + case 0x50: /* Block Erase */ +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("erase FLASH %08x %08x\n", + (offset & ~(flash->block_size - 1)), + flash->block_size); +#endif + memset(datap + (offset & ~(flash->block_size - 1)), 0xff, flash->block_size); + break; + default: + break; + } + + flash_state_reset(flash); + break; + } +} + +static uint32_t +flash_readb(void *opaque, target_phys_addr_t offset) +{ + x49gp_flash_t *flash = opaque; + uint8_t *datap = flash->data; + unsigned short temp; + uint32_t shift; + unsigned char data; + + if (flash->state == FLASH_STATE_NORMAL) { + offset -= (target_phys_addr_t) phys_ram_base; + data = *(datap + offset); + } else { + offset -= 0; + temp = flash_get_halfword(flash, offset & ~(1)); + shift = (offset & 1) << 3; + data = (temp >> shift) & 0xff; + } + +#ifdef DEBUG_X49GP_FLASH_READ + printf("read FLASH 1 (state %u) at offset %08x: %02x\n", + flash->state, offset, data); +#endif + + return data; +} + +static uint32_t +flash_readw(void *opaque, target_phys_addr_t offset) +{ + x49gp_flash_t *flash = opaque; + uint8_t *datap = flash->data; + uint32_t data; + + if (flash->state == FLASH_STATE_NORMAL) { + offset -= (target_phys_addr_t) phys_ram_base; + data = lduw_p(datap + offset); + } else { + offset -= 0; + data = flash_get_halfword(flash, offset); + } + +#ifdef DEBUG_X49GP_FLASH_READ + printf("read FLASH 2 (state %u) at offset %08x: %04x\n", + flash->state, offset, data); +#endif + + return data; +} + +static uint32_t +flash_readl(void *opaque, target_phys_addr_t offset) +{ + x49gp_flash_t *flash = opaque; + uint8_t *datap = flash->data; + uint32_t data; + + if (flash->state == FLASH_STATE_NORMAL) { + offset -= (target_phys_addr_t) phys_ram_base; + data = ldl_p(datap + offset); + } else { + offset -= 0; + data = (flash_get_halfword(flash, offset + 2) << 16) | + (flash_get_halfword(flash, offset + 0) << 0); + } + +#ifdef DEBUG_X49GP_FLASH_READ + printf("read FLASH 4 (state %u) at offset %08x: %08x\n", + flash->state, offset, data); +#endif + + return data; +} + +static void +flash_writeb(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_flash_t *flash = opaque; + uint32_t shift; + + if (flash->state == FLASH_STATE_NORMAL) + offset -= (target_phys_addr_t) phys_ram_base; + else + offset -= 0; + + data &= 0xff; + +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("write FLASH 1 (state %u) at offset %08x: %02x\n", + flash->state, offset, data); +#endif + + /* + * This does not issue read-modify-write, i.e. you will get + * broken data in FLASH memory. This would be the case with + * real hardware, too. + */ + shift = (offset & 1) << 3; + flash_put_halfword(flash, offset & ~(1), data << shift); +} + +static void +flash_writew(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_flash_t *flash = opaque; + + if (flash->state == FLASH_STATE_NORMAL) + offset -= (target_phys_addr_t) phys_ram_base; + else + offset -= 0; + + data &= 0xffff; + +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("write FLASH 2 (state %u) at offset %08x: %04x\n", + flash->state, offset, data); +#endif + + flash_put_halfword(flash, offset, data); +} + +static void +flash_writel(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_flash_t *flash = opaque; + + if (flash->state == FLASH_STATE_NORMAL) + offset -= (target_phys_addr_t) phys_ram_base; + else + offset -= 0; + +#ifdef DEBUG_X49GP_FLASH_WRITE + printf("write FLASH 4 (state %u) at offset %08x: %08x\n", + flash->state, offset, data); +#endif + + flash_put_halfword(flash, offset + 2, (data >> 16) & 0xffff); + flash_put_halfword(flash, offset + 0, (data >> 0) & 0xffff); +} + +static int +flash_load(x49gp_module_t *module, GKeyFile *key) +{ + x49gp_flash_t *flash = module->user_data; + char *filename; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + filename = x49gp_module_get_filename(module, key, "filename"); + if (NULL == filename) { + fprintf(stderr, "%s: %s:%u: key \"filename\" not found\n", + module->name, __FUNCTION__, __LINE__); + return -1; + } + + flash->fd = open(filename, O_RDWR); + if (flash->fd < 0) { + fprintf(stderr, "%s: %s:%u: open %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + return -1; + } + + flash->data = mmap(phys_ram_base + flash->offset, SST29VF160_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + flash->fd, 0); + if (flash->data == (void *) -1) { + fprintf(stderr, "%s: %s:%u: mmap %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + close(flash->fd); + flash->fd = -1; + return -1; + } + flash->size = SST29VF160_SIZE; + + g_free(filename); + return 0; +} + +static int +flash_save(x49gp_module_t *module, GKeyFile *config) +{ + x49gp_flash_t *flash = module->user_data; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + error = msync(flash->data, flash->size, MS_ASYNC); + if (error) { + fprintf(stderr, "%s:%u: msync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + error = fsync(flash->fd); + if (error) { + fprintf(stderr, "%s:%u: fsync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + return 0; +} + +static int +flash_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + x49gp_flash_t *flash = module->user_data; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + flash_state_reset(flash); + return 0; +} + +static CPUReadMemoryFunc *flash_readfn[] = +{ + flash_readb, + flash_readw, + flash_readl +}; + +static CPUWriteMemoryFunc *flash_writefn[] = +{ + flash_writeb, + flash_writew, + flash_writel +}; + +static int +flash_init(x49gp_module_t *module) +{ + x49gp_flash_t *flash; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + flash = malloc(sizeof(x49gp_flash_t)); + if (NULL == flash) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->name, __FUNCTION__, __LINE__); + return -1; + } + memset(flash, 0, sizeof(x49gp_flash_t)); + + flash->vendor_ID = SST29VF160_VENDOR_ID; + flash->device_ID = SST29VF160_DEVICE_ID; + flash->cfi_data = sst29vf160_cfi_data; + flash->cfi_size = SST29VF160_CFI_SIZE; + flash->sector_size = SST29VF160_SECTOR_SIZE; + flash->block_size = SST29VF160_BLOCK_SIZE; + flash->fd = -1; + + module->user_data = flash; + +#ifdef QEMU_OLD + flash->iotype = cpu_register_io_memory(0, flash_readfn, + flash_writefn, flash); +#else + flash->iotype = cpu_register_io_memory(flash_readfn, + flash_writefn, flash); +#endif + + flash->data = (void *) -1; + flash->offset = phys_ram_size; + phys_ram_size += SST29VF160_SIZE; + + cpu_register_physical_memory(0x00000000, SST29VF160_SIZE, + flash->offset | flash->iotype | IO_MEM_ROMD); + + return 0; +} + +static int +flash_exit(x49gp_module_t *module) +{ + x49gp_flash_t *flash; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + flash = module->user_data; + + if (flash->data != (void *) -1) { + munmap(flash->data, flash->size); + } + if (flash->fd) { + close(flash->fd); + } + + free(flash); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_flash_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "flash", flash_init, flash_exit, + flash_reset, flash_load, flash_save, NULL, + &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/gdbstub.c b/gdbstub.c new file mode 100644 index 0000000..775a239 --- /dev/null +++ b/gdbstub.c @@ -0,0 +1,672 @@ +/* + * gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "gdbstub.h" + +#ifdef _WIN32 +/* XXX: these constants may be independent of the host ones even for Unix */ +#ifndef SIGTRAP +#define SIGTRAP 5 +#endif +#ifndef SIGINT +#define SIGINT 2 +#endif +#else +#include +#endif + +#define DEBUG_GDB + +enum RSState { + RS_IDLE, + RS_GETLINE, + RS_CHKSUM1, + RS_CHKSUM2, + RS_SYSCALL, +}; + +typedef struct GDBState { + CPUState *env; /* current CPU */ + enum RSState state; /* parsing state */ + char line_buf[4096]; + int line_buf_index; + int line_csum; + char last_packet[4100]; + int last_packet_len; + int fd; + int running_state; +} GDBState; + +/* XXX: This is not thread safe. Do we care? */ +static int gdbserver_fd = -1; + +/* XXX: remove this hack. */ +static GDBState gdbserver_state; + +static int get_char(GDBState *s) +{ + uint8_t ch; + int ret; + + for(;;) { + ret = recv(s->fd, &ch, 1, 0); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return -1; + } else if (ret == 0) { + return -1; + } else { + break; + } + } + return ch; +} + +/* GDB stub state for use by semihosting syscalls. */ +static GDBState *gdb_syscall_state; +static gdb_syscall_complete_cb gdb_current_syscall_cb; + +enum { + GDB_SYS_UNKNOWN, + GDB_SYS_ENABLED, + GDB_SYS_DISABLED, +} gdb_syscall_mode; + +/* If gdb is connected when the first semihosting syscall occurs then use + remote gdb syscalls. Otherwise use native file IO. */ +int use_gdb_syscalls(void) +{ + if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { + gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED + : GDB_SYS_DISABLED); + } + return gdb_syscall_mode == GDB_SYS_ENABLED; +} + +static void put_buffer(GDBState *s, const uint8_t *buf, int len) +{ + int ret; + + while (len > 0) { + ret = send(s->fd, buf, len, 0); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return; + } else { + buf += ret; + len -= ret; + } + } +} + +static inline int fromhex(int v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + else if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + else if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + else + return 0; +} + +static inline int tohex(int v) +{ + if (v < 10) + return v + '0'; + else + return v - 10 + 'a'; +} + +static void memtohex(char *buf, const uint8_t *mem, int len) +{ + int i, c; + char *q; + q = buf; + for(i = 0; i < len; i++) { + c = mem[i]; + *q++ = tohex(c >> 4); + *q++ = tohex(c & 0xf); + } + *q = '\0'; +} + +static void hextomem(uint8_t *mem, const char *buf, int len) +{ + int i; + + for(i = 0; i < len; i++) { + mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]); + buf += 2; + } +} + +/* return -1 if error, 0 if OK */ +static int put_packet(GDBState *s, char *buf) +{ + int len, csum, i; + char *p; + +#ifdef DEBUG_GDB + printf("reply='%s'\n", buf); +#endif + + for(;;) { + p = s->last_packet; + *(p++) = '$'; + len = strlen(buf); + memcpy(p, buf, len); + p += len; + csum = 0; + for(i = 0; i < len; i++) { + csum += buf[i]; + } + *(p++) = '#'; + *(p++) = tohex((csum >> 4) & 0xf); + *(p++) = tohex((csum) & 0xf); + + s->last_packet_len = p - s->last_packet; + put_buffer(s, (uint8_t *) s->last_packet, s->last_packet_len); + + i = get_char(s); + if (i < 0) + return -1; + if (i == '+') + break; + } + return 0; +} + +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + /* 16 core integer registers (4 bytes each). */ + for (i = 0; i < 16; i++) + { + *(uint32_t *)ptr = tswapl(env->regs[i]); + ptr += 4; + } + /* 8 FPA registers (12 bytes each), FPS (4 bytes). + Not yet implemented. */ + memset (ptr, 0, 8 * 12 + 4); + ptr += 8 * 12 + 4; + /* CPSR (4 bytes). */ + *(uint32_t *)ptr = tswapl (cpsr_read(env)); + ptr += 4; + + return ptr - mem_buf; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + /* Core integer registers. */ + for (i = 0; i < 16; i++) + { + env->regs[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + /* Ignore FPA regs and scr. */ + ptr += 8 * 12 + 4; + cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); +} + +static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) +{ + const char *p; + int ch, reg_size, type; + char buf[4096]; + uint8_t mem_buf[2000]; + uint32_t *registers; + target_ulong addr, len; + +#ifdef DEBUG_GDB + printf("command='%s'\n", line_buf); +#endif + p = line_buf; + ch = *p++; + switch(ch) { + case '?': + /* TODO: Make this return the correct value for user-mode. */ + snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); + put_packet(s, buf); + break; + case 'c': + if (*p != '\0') { + addr = strtoull(p, (char **)&p, 16); + env->regs[15] = addr; + } + s->running_state = 1; + return RS_IDLE; + case 's': + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); + env->regs[15] = addr; + } + cpu_single_step(env, 1); + s->running_state = 1; + return RS_IDLE; + case 'F': + { + target_ulong ret; + target_ulong err; + + ret = strtoull(p, (char **)&p, 16); + if (*p == ',') { + p++; + err = strtoull(p, (char **)&p, 16); + } else { + err = 0; + } + if (*p == ',') + p++; + type = *p; + if (gdb_current_syscall_cb) + gdb_current_syscall_cb(s->env, ret, err); + if (type == 'C') { + put_packet(s, "T02"); + } else { + s->running_state = 1; + } + } + break; + case 'g': + reg_size = cpu_gdb_read_registers(env, mem_buf); + memtohex(buf, mem_buf, reg_size); + put_packet(s, buf); + break; + case 'G': + registers = (void *)mem_buf; + len = strlen(p) / 2; + hextomem((uint8_t *)registers, p, len); + cpu_gdb_write_registers(env, mem_buf, len); + put_packet(s, "OK"); + break; + case 'm': + addr = strtoull(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoull(p, NULL, 16); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { + put_packet (s, "E14"); + } else { + memtohex(buf, mem_buf, len); + put_packet(s, buf); + } + break; + case 'M': + addr = strtoull(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoull(p, (char **)&p, 16); + if (*p == ':') + p++; + hextomem(mem_buf, p, len); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) + put_packet(s, "E14"); + else + put_packet(s, "OK"); + break; + case 'Z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoull(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoull(p, (char **)&p, 16); + if (type == 0 || type == 1) { + if ( +#ifdef QEMU_OLD + cpu_breakpoint_insert(env, addr) < 0 +#else + cpu_breakpoint_insert(env, addr, BP_GDB, NULL) < 0 +#endif + ) + goto breakpoint_error; + put_packet(s, "OK"); + } else { + breakpoint_error: + put_packet(s, "E22"); + } + break; + case 'z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoull(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoull(p, (char **)&p, 16); + if (type == 0 || type == 1) { +#ifdef QEMU_OLD + cpu_breakpoint_remove(env, addr); +#else + cpu_breakpoint_remove(env, addr, BP_GDB); +#endif + put_packet(s, "OK"); + } else { + goto breakpoint_error; + } + break; + default: + // unknown_command: + /* put empty packet */ + buf[0] = '\0'; + put_packet(s, buf); + break; + } + return RS_IDLE; +} + +extern void tb_flush(CPUState *env); + +/* Send a gdb syscall request. + This accepts limited printf-style format specifiers, specifically: + %x - target_ulong argument printed in hex. + %s - string pointer (target_ulong) and length (int) pair. */ +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) +{ + va_list va; + char buf[256]; + char *p; + target_ulong addr; + GDBState *s; + + s = gdb_syscall_state; + if (!s) + return; + gdb_current_syscall_cb = cb; + s->state = RS_IDLE; + va_start(va, fmt); + p = buf; + *(p++) = 'F'; + while (*fmt) { + if (*fmt == '%') { + fmt++; + switch (*fmt++) { + case 'x': + addr = va_arg(va, target_ulong); + p += sprintf(p, TARGET_FMT_lx, addr); + break; + case 's': + addr = va_arg(va, target_ulong); + p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); + break; + default: + fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n", + fmt - 1); + break; + } + } else { + *(p++) = *(fmt++); + } + } + va_end(va); + put_packet(s, buf); +#ifdef QEMU_OLD + cpu_interrupt(s->env, CPU_INTERRUPT_EXIT); +#else + cpu_exit(s->env); +#endif +} + +static void gdb_read_byte(GDBState *s, int ch) +{ + CPUState *env = s->env; + char buf[256]; + int i, csum; + char reply[1]; + +printf("%s: state %u, byte %02x (%c)\n", __FUNCTION__, s->state, ch, ch); +fflush(stdout); + + switch(s->state) { + case RS_IDLE: + if (ch == '$') { + s->line_buf_index = 0; + s->state = RS_GETLINE; + } else if (ch == 0x03) { + snprintf(buf, sizeof(buf), "S%02x", SIGINT); + put_packet(s, buf); + } + break; + case RS_GETLINE: + if (ch == '#') { + s->state = RS_CHKSUM1; + } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { + s->state = RS_IDLE; + } else { + s->line_buf[s->line_buf_index++] = ch; + } + break; + case RS_CHKSUM1: + s->line_buf[s->line_buf_index] = '\0'; + s->line_csum = fromhex(ch) << 4; + s->state = RS_CHKSUM2; + break; + case RS_CHKSUM2: + s->line_csum |= fromhex(ch); + csum = 0; + for(i = 0; i < s->line_buf_index; i++) { + csum += s->line_buf[i]; + } + if (s->line_csum != (csum & 0xff)) { + reply[0] = '-'; + put_buffer(s, (uint8_t *) reply, 1); + s->state = RS_IDLE; + } else { + reply[0] = '+'; + put_buffer(s, (uint8_t *) reply, 1); + s->state = gdb_handle_packet(s, env, s->line_buf); + } + break; + default: + abort(); + } +} + +int +gdb_handlesig (CPUState *env, int sig) +{ + GDBState *s; + char buf[256]; + int n; + + if (gdbserver_fd < 0) + return sig; + + s = &gdbserver_state; + +printf("%s: sig: %u\n", __FUNCTION__, sig); +fflush(stdout); + + /* disable single step if it was enabled */ + cpu_single_step(env, 0); + tb_flush(env); + + if (sig != 0) + { + snprintf(buf, sizeof(buf), "S%02x", sig); + put_packet(s, buf); + } + + sig = 0; + s->state = RS_IDLE; + s->running_state = 0; + while (s->running_state == 0) { + n = read (s->fd, buf, 256); + if (n > 0) + { + int i; + +printf("%s: read: %d\n", __FUNCTION__, n); +fflush(stdout); + + for (i = 0; i < n; i++) + gdb_read_byte (s, buf[i]); + } + else if (n == 0 || errno != EAGAIN) + { + /* XXX: Connection closed. Should probably wait for annother + connection before continuing. */ + return sig; + } + } + return sig; +} + +int +gdb_poll (CPUState *env) +{ + GDBState *s; + struct pollfd pfd; + + if (gdbserver_fd < 0) + return 0; + + s = &gdbserver_state; + + pfd.fd = s->fd; + pfd.events = POLLIN | POLLHUP; + + if (poll(&pfd, 1, 0) <= 0) { + if (errno != EAGAIN) + return 0; + return 0; + } + +printf("%s: revents: %08x\n", __FUNCTION__, pfd.revents); +fflush(stdout); + + if (pfd.revents & (POLLIN | POLLHUP)) + return 1; + + return 0; +} + +/* Tell the remote gdb that the process has exited. */ +void gdb_exit(CPUState *env, int code) +{ + GDBState *s; + char buf[4]; + + if (gdbserver_fd < 0) + return; + + s = &gdbserver_state; + + snprintf(buf, sizeof(buf), "W%02x", code); + put_packet(s, buf); +} + + +static void gdb_accept(void *opaque) +{ + GDBState *s; + struct sockaddr_in sockaddr; + socklen_t len; + int val, fd; + + for(;;) { + len = sizeof(sockaddr); + fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len); + if (fd < 0 && errno != EINTR) { + perror("accept"); + return; + } else if (fd >= 0) { + break; + } + } + + /* set short latency */ + val = 1; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + + s = &gdbserver_state; + memset (s, 0, sizeof (GDBState)); + s->env = first_cpu; /* XXX: allow to change CPU */ + s->fd = fd; + + gdb_syscall_state = s; + + fcntl(fd, F_SETFL, O_NONBLOCK); +} + +static int gdbserver_open(int port) +{ + struct sockaddr_in sockaddr; + int fd, val, ret; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = 0; + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + return fd; +} + +int gdbserver_start(int port) +{ + gdbserver_fd = gdbserver_open(port); + if (gdbserver_fd < 0) + return -1; + /* accept connections */ + gdb_accept (NULL); + return 0; +} diff --git a/gdbstub.h b/gdbstub.h new file mode 100644 index 0000000..b3330e5 --- /dev/null +++ b/gdbstub.h @@ -0,0 +1,18 @@ +#ifndef GDBSTUB_H +#define GDBSTUB_H + +#define DEFAULT_GDBSTUB_PORT 1234 + +typedef void (*gdb_syscall_complete_cb)(CPUState *env, + target_ulong ret, target_ulong err); + +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...); +int use_gdb_syscalls(void); + +int gdb_poll(CPUState *); + +int gdb_handlesig (CPUState *, int); +void gdb_exit(CPUState *, int); +int gdbserver_start(int); + +#endif diff --git a/hex2bin.c b/hex2bin.c new file mode 100644 index 0000000..fed518b --- /dev/null +++ b/hex2bin.c @@ -0,0 +1,117 @@ +/* $Id: hex2bin.c,v 1.3 2008/12/11 12:18:17 ecd Exp $ + * + * $Log: hex2bin.c,v $ + * Revision 1.3 2008/12/11 12:18:17 ecd + * major rework to qemu + * + * Revision 1.1 2006-08-20 17:26:07 ecd + * Modularize most stuff, IO_PORT, INTC, ARM, and MMU still missing. + * + * Revision 1.1 2002/06/19 08:19:39 ecd + * Add Lattice/Xilinx tools + * + * Revision 1.1 2002/01/04 10:46:48 ecd + * initial import + * + * Revision 1.1 1999/12/09 10:53:33 ecd + * add Xilinx conversion tool + * + */ + +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + unsigned char *input, *p; + unsigned char *memory = NULL; + size_t size; + int in, out; + int i; + + if (argc < 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + + if (!strcmp(argv[1], "-")) + in = 0; + else { + in = open(argv[1], O_RDONLY); + if (in < 0) { + perror(argv[1]); + exit(1); + } + } + + if (!strcmp(argv[2], "-")) + out = 1; + else { + out = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (out < 0) { + perror(argv[2]); + exit(1); + } + } + + size = lseek(in, 0, SEEK_END); + lseek(in, 0, SEEK_SET); + + input = (unsigned char *)malloc(size); + if (!input) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(1); + } + + if (read(in, input, size) != size) { + perror("read"); + exit(1); + } + + close(in); + + memory = malloc(size >> 1); + if (!memory) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(1); + } + + p = input; + for (i = 0; i < (size >> 1); i++) { + if ('0' <= *p && *p <= '9') + memory[i] = (*p - '0') << 0; + else if ('a' <= *p && *p <= 'f') + memory[i] = (*p - 'a' + 10) << 0; + else if ('A' <= *p && *p <= 'F') + memory[i] = (*p - 'A' + 10) << 0; + else { + fprintf(stderr, "%s: parse error at byte %d\n", + argv[0], i); + exit(1); + } + p++; + if ('0' <= *p && *p <= '9') + memory[i] |= (*p - '0') << 4; + else if ('a' <= *p && *p <= 'f') + memory[i] |= (*p - 'a' + 10) << 4; + else if ('A' <= *p && *p <= 'F') + memory[i] |= (*p - 'A' + 10) << 4; + else { + fprintf(stderr, "%s: parse error at byte %d\n", + argv[0], i); + exit(1); + } + p++; + } + + write(out, memory, size >> 1); + close(out); + + return 0; +} diff --git a/hp49g+.png b/hp49g+.png new file mode 100644 index 0000000..daac065 Binary files /dev/null and b/hp49g+.png differ diff --git a/hp49g+small-notext.png b/hp49g+small-notext.png new file mode 100644 index 0000000..39515b5 Binary files /dev/null and b/hp49g+small-notext.png differ diff --git a/hp49g-u.bin b/hp49g-u.bin new file mode 100644 index 0000000..6f47b90 Binary files /dev/null and b/hp49g-u.bin differ diff --git a/hp50g-hack.png b/hp50g-hack.png new file mode 100644 index 0000000..e61cf53 Binary files /dev/null and b/hp50g-hack.png differ diff --git a/hp50g.png b/hp50g.png new file mode 100644 index 0000000..0733f27 Binary files /dev/null and b/hp50g.png differ diff --git a/include/.svn/all-wcprops b/include/.svn/all-wcprops new file mode 100644 index 0000000..2fe3d60 --- /dev/null +++ b/include/.svn/all-wcprops @@ -0,0 +1,113 @@ +K 25 +svn:wc:ra_dav:version-url +V 33 +/p/x49gp/code/!svn/ver/10/include +END +block.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/10/include/block.h +END +s3c2410_timer.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/include/s3c2410_timer.h +END +s3c2410.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/p/x49gp/code/!svn/ver/1/include/s3c2410.h +END +byteorder.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/include/byteorder.h +END +bitmaps.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/p/x49gp/code/!svn/ver/1/include/bitmaps.h +END +x49gp_types.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/include/x49gp_types.h +END +bitmap_font.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/include/bitmap_font.h +END +block_int.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/10/include/block_int.h +END +symbol.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/include/symbol.h +END +x49gp_ui.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/include/x49gp_ui.h +END +x49gp.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/10/include/x49gp.h +END +s3c2410_power.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/1/include/s3c2410_power.h +END +list.h +K 25 +svn:wc:ra_dav:version-url +V 40 +/p/x49gp/code/!svn/ver/10/include/list.h +END +x49gp_timer.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/include/x49gp_timer.h +END +s3c2410_intc.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/include/s3c2410_intc.h +END +saturn.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/include/saturn.h +END +s3c2410_mmu.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/include/s3c2410_mmu.h +END +glyphname.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/include/glyphname.h +END diff --git a/include/.svn/entries b/include/.svn/entries new file mode 100644 index 0000000..c7b820f --- /dev/null +++ b/include/.svn/entries @@ -0,0 +1,643 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/include +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +block.h +file + + + + +2013-08-23T00:54:46.000000Z +724d77629c1c152eac647c68e3738115 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +6833 + +s3c2410_timer.h +file + + + + +2013-08-23T00:54:46.000000Z +f54b86fa985ffc88917da28c2a8ac118 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1389 + +s3c2410.h +file + + + + +2013-08-23T00:54:46.000000Z +d3d2551d57134aef5991fc4342a4ecc6 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +11906 + +byteorder.h +file + + + + +2013-08-23T00:54:46.000000Z +b7749ae9c1359d8e43981ba94bdc5977 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1981 + +bitmaps.h +file + + + + +2013-08-23T00:54:46.000000Z +f7f9b1755e8733d5d088311951eddc8e +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +462 + +x49gp_types.h +file + + + + +2013-08-23T00:54:46.000000Z +04fdff61e46ad293425cb4bbd17dc90d +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +484 + +bitmap_font.h +file + + + + +2013-08-23T00:54:46.000000Z +0fc4834669f0ab7ef08b150810c0ab95 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +772 + +block_int.h +file + + + + +2013-08-23T00:54:46.000000Z +e7a9a03638da2682a1c2d32d8af0fe58 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4267 + +symbol.h +file + + + + +2013-08-23T00:54:46.000000Z +e3765ce8fad75a0f7af53e851dfc0f4b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1710 + +CVS +dir + +x49gp_ui.h +file + + + + +2013-08-23T00:54:46.000000Z +c0038310fddb0a91cbac539b61340f12 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +2224 + +x49gp.h +file + + + + +2013-08-23T00:54:46.000000Z +c6f8a2036694a0ee43da6c109ddaa239 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3602 + +s3c2410_power.h +file + + + + +2013-08-23T00:54:46.000000Z +f82936ec6c6ddefbcb7184f8955f5b1e +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +759 + +list.h +file + + + + +2013-08-23T00:54:46.000000Z +58c07e25aacaaf9d4274bef65a77f470 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +18688 + +x49gp_timer.h +file + + + + +2013-08-23T00:54:46.000000Z +2500b1c34f6b949b3abcfbe1c1e4fbe6 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +818 + +saturn.h +file + + + + +2013-08-23T00:54:46.000000Z +fcd320a635f3f67bff402c3d28789e31 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +812 + +s3c2410_intc.h +file + + + + +2013-08-23T00:54:46.000000Z +58055caa3e8e564481a947e137e235a8 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1678 + +s3c2410_mmu.h +file + + + + +2013-08-23T00:54:46.000000Z +9f8f0272ca3986e74b9b9b78ba4ef78d +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +660 + +glyphname.h +file + + + + +2013-08-23T00:54:46.000000Z +3a3fac3ab41ca7c03a2f2103517f4153 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +5982 + diff --git a/include/.svn/text-base/bitmap_font.h.svn-base b/include/.svn/text-base/bitmap_font.h.svn-base new file mode 100644 index 0000000..ef99d6f --- /dev/null +++ b/include/.svn/text-base/bitmap_font.h.svn-base @@ -0,0 +1,37 @@ +/* $Id: bitmap_font.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BITMAP_FONT_H +#define _X49GP_BITMAP_FONT_H 1 + +typedef struct { + const char *name; + int width; + int kern; + int ascent; + int descent; + const unsigned char *bits; +} bitmap_glyph_t; + +typedef struct { + int ascent; + int descent; + bitmap_glyph_t glyphs[]; +} bitmap_font_t; + +#define GLYPH(font, name) \ + { \ + #name, \ + font##_##name##_width - font##_##name##_x_hot, \ + -font##_##name##_x_hot, \ + font##_##name##_y_hot + 1, \ + font##_##name##_y_hot + 1 - font##_##name##_height, \ + font##_##name##_bits \ + } + +#define SPACE(name, width, kern) \ + { name, width, kern, 0, 0, NULL } + +extern const bitmap_font_t tiny_font; + +#endif /* !(_X49GP_BITMAP_FONT_H) */ diff --git a/include/.svn/text-base/bitmaps.h.svn-base b/include/.svn/text-base/bitmaps.h.svn-base new file mode 100644 index 0000000..de8e25d --- /dev/null +++ b/include/.svn/text-base/bitmaps.h.svn-base @@ -0,0 +1,21 @@ +/* $Id: bitmaps.h,v 1.9 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BITMAPS_H +#define _X49GP_BITMAPS_H 1 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif /* !(_X49GP_BITMAPS_H) */ diff --git a/include/.svn/text-base/block.h.svn-base b/include/.svn/text-base/block.h.svn-base new file mode 100644 index 0000000..e4c285a --- /dev/null +++ b/include/.svn/text-base/block.h.svn-base @@ -0,0 +1,187 @@ +/* $Id: block.h,v 1.1 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef BLOCK_H +#define BLOCK_H 1 + +#include + +#define BDRV_O_RDONLY 0x0000 +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_ACCESS 0x0003 +#define BDRV_O_CREAT 0x0004 /* create an empty file */ +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save + writes in a snapshot */ +#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to + use a disk image format on top of + it (default for + bdrv_file_open()) */ + +#ifdef QEMU_OLD +typedef struct BlockDriverState BlockDriverState; +#endif +typedef struct BlockDriver BlockDriver; +typedef struct SnapshotInfo QEMUSnapshotInfo; +typedef struct BlockDriverInfo BlockDriverInfo; +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_host_device; +extern BlockDriver bdrv_qcow; +extern BlockDriver bdrv_vvfat; + +void bdrv_init(void); +int bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_delete(BlockDriverState *bs); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags); + +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); + +#ifdef QEMU_OLD +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + int (*bdrv_make_empty)(BlockDriverState *bs); + /* aio */ + BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb); + int aiocb_size; + + const char *protocol_name; + int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count); + int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count); + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int64_t (*bdrv_getlength)(BlockDriverState *bs); + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + + int (*bdrv_snapshot_create)(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); + int (*bdrv_snapshot_goto)(BlockDriverState *bs, + const char *snapshot_id); + int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); + int (*bdrv_snapshot_list)(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag); + int (*bdrv_set_locked)(BlockDriverState *bs, int locked); + + BlockDriverAIOCB *free_aiocb; + struct BlockDriver *next; +}; + +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + int media_changed; + + BlockDriverState *backing_hd; +// /* async read/write emulation */ +// +// void *sync_aiocb; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs, translation; + int type; + char device_name[32]; + BlockDriverState *next; +}; + +void *qemu_malloc(size_t size); +void *qemu_mallocz(size_t size); +void qemu_free(void *ptr); + +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +#endif /* QEMU_OLD */ + +#ifndef QEMU_OLD +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); +void bdrv_flush(BlockDriverState *bs); + +/* timers */ + +typedef struct QEMUClock QEMUClock; +typedef void QEMUTimerCB(void *opaque); + +/* The real time clock should be used only for stuff which does not + change the virtual machine state, as it is run even if the virtual + machine is stopped. The real time clock has a frequency of 1000 + Hz. */ +extern QEMUClock *rt_clock; + +int64_t qemu_get_clock(QEMUClock *clock); + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); +void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +int qemu_timer_pending(QEMUTimer *ts); + +extern int64_t ticks_per_sec; + +struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; +}; + +#endif + +#endif /* !(BLOCK_H) */ diff --git a/include/.svn/text-base/block_int.h.svn-base b/include/.svn/text-base/block_int.h.svn-base new file mode 100644 index 0000000..581679a --- /dev/null +++ b/include/.svn/text-base/block_int.h.svn-base @@ -0,0 +1,104 @@ +/* + * QEMU System Emulator block driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCK_INT_H +#define BLOCK_INT_H + +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + int (*bdrv_make_empty)(BlockDriverState *bs); + + const char *protocol_name; + int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count); + int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count); + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int64_t (*bdrv_getlength)(BlockDriverState *bs); + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag); + int (*bdrv_set_locked)(BlockDriverState *bs, int locked); + + struct BlockDriver *next; +}; + +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + int media_changed; + + BlockDriverState *backing_hd; + /* async read/write emulation */ + + void *sync_aiocb; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs, translation; + int type; + char device_name[32]; + BlockDriverState *next; +}; + +void get_tmp_filename(char *filename, int size); + +#endif /* BLOCK_INT_H */ diff --git a/include/.svn/text-base/byteorder.h.svn-base b/include/.svn/text-base/byteorder.h.svn-base new file mode 100644 index 0000000..72fb035 --- /dev/null +++ b/include/.svn/text-base/byteorder.h.svn-base @@ -0,0 +1,91 @@ +/* $Id: byteorder.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BYTEORDER_H +#define _X49GP_BYTEORDER_H 1 + +#include + +static __inline__ uint16_t swab16(uint16_t x) +{ + return ((x & 0xff00) >> 8) | + ((x & 0x00ff) << 8); +} + +static __inline__ uint32_t swab32(uint32_t x) +{ + return ((x & 0xff000000) >> 24) | + ((x & 0x00ff0000) >> 8) | + ((x & 0x0000ff00) << 8) | + ((x & 0x000000ff) << 24); +} + +#ifdef __sparc__ + +#define ASI_PL 0x88 /* Primary, implicit, little endian. */ + +static __inline__ uint16_t __load_le16(const uint16_t *p) +{ + uint16_t x; + + __asm__ __volatile__ ("lduha [%1] %2, %0" + : "=r" (x) + : "r" (p), "i" (ASI_PL)); + return x; +} + +static __inline__ uint32_t __load_le32(const uint32_t *p) +{ + uint32_t x; + + __asm__ __volatile__ ("lduwa [%1] %2, %0" + : "=r" (x) + : "r" (p), "i" (ASI_PL)); + return x; +} + +static __inline__ void __store_le16(uint16_t *p, uint16_t x) +{ + __asm__ __volatile__ ("stha %0, [%1] %2" + : /* no outputs */ + : "r" (x), "r" (p), "i" (ASI_PL)); +} + +static __inline__ void __store_le32(uint32_t *p, uint32_t x) +{ + __asm__ __volatile__ ("stwa %0, [%1] %2" + : /* no outputs */ + : "r" (x), "r" (p), "i" (ASI_PL)); +} + +#endif /* __sparc__ */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +#define load_le16(p) (*(p)) +#define store_le16(p, x) (*(p) = (x)) +#define load_le32(p) (*(p)) +#define store_le32(p, x) (*(p) = (x)) + +#elif __BYTE_ORDER == __BIG_ENDIAN + +#define le16_to_cpu(x) swab16(x) +#define cpu_to_le16(x) swab16(x) +#define le32_to_cpu(x) swab32(x) +#define cpu_to_le32(x) swab32(x) + +#define load_le16(p) __load_le16(p) +#define store_le16(p, x) __store_le16(p, x) +#define load_le32(p) __load_le32(p) +#define store_le32(p, x) __store_le32(p, x) + +#else +#error "Cannot determine host byteorder" +#endif + +#endif /* !(_X49GP_BYTEORDER_H) */ diff --git a/include/.svn/text-base/glyphname.h.svn-base b/include/.svn/text-base/glyphname.h.svn-base new file mode 100644 index 0000000..787d8e9 --- /dev/null +++ b/include/.svn/text-base/glyphname.h.svn-base @@ -0,0 +1,238 @@ +/* $Id: glyphname.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_GLYPHNAME_H +#define _X49GP_GLYPHNAME_H 1 + +typedef struct { + const char *name; + gunichar unichar; +} x49gp_glyph_t; + +static const x49gp_glyph_t x49gp_glyphs[] = +{ + { "exclamdown", 0x00a1 }, + { "cent", 0x00a2 }, + { "sterling", 0x00a3 }, + { "fraction", 0x2044 }, + { "yen", 0x00a5 }, + { "florin", 0x0192 }, + { "section", 0x00a7 }, + { "currency", 0x00a4 }, + { "quotesingle", 0x0027 }, + { "quotedblleft", 0x201c }, + { "guillemotleft", 0x00ab }, + { "guilsinglleft", 0x2039 }, + { "guilsinglright", 0x203a }, + { "fi", 0xfb01 }, + { "fl", 0xfb02 }, + { "endash", 0x2013 }, + { "dagger", 0x2020 }, + { "daggerdbl", 0x2021 }, + { "periodcentered", 0x00b7 }, + { "paragraph", 0x00b6 }, + { "bullet", 0x2022 }, + { "quotesinglbase", 0x201a }, + { "quotedblbase", 0x201e }, + { "quotedblright", 0x201d }, + { "guillemotright", 0x00bb }, + { "ellipsis", 0x2026 }, + { "perthousand", 0x2030 }, + { "questiondown", 0x00bf }, + { "grave", 0x0060 }, + { "acute", 0x00b4 }, + { "circumflex", 0x02c6 }, + { "tilde", 0x02dc }, + { "macron", 0x00af }, + { "breve", 0x02d8 }, + { "dotaccent", 0x02d9 }, + { "dieresis", 0x00a8 }, + { "ring", 0x02da }, + { "cedilla", 0x00b8 }, + { "hungarumlaut", 0x02dd }, + { "ogonek", 0x02db }, + { "caron", 0x02c7 }, + { "emdash", 0x2014 }, + { "AE", 0x00c6 }, + { "ordfeminine", 0x00aa }, + { "Lslash", 0x0141 }, + { "Oslash", 0x00d8 }, + { "OE", 0x0152 }, + { "ordmasculine", 0x00ba }, + { "ae", 0x00e6 }, + { "dotlessi", 0x0131 }, + { "lslash", 0x0142 }, + { "oslash", 0x00f8 }, + { "oe", 0x0153 }, + { "germandbls", 0x00df }, + { "Udieresis", 0x00dc }, + { "Uacute", 0x00da }, + { "Scedilla", 0x015e }, + { "Tcaron", 0x0164 }, + { "Scaron", 0x0160 }, + { "Rcaron", 0x0158 }, + { "Racute", 0x0154 }, + { "Sacute", 0x015a }, + { "Otilde", 0x00d5 }, + { "ucircumflex", 0x00fb }, + { "Ohungarumlaut", 0x0150 }, + { "Uhungarumlaut", 0x0170 }, + { "Yacute", 0x00dd }, + { "Eth", 0x00d0 }, + { "Dcroat", 0x0110 }, + { "Zacute", 0x0179 }, + { "Uring", 0x016e }, + { "gbreve", 0x011f }, + { "eogonek", 0x0119 }, + { "edotaccent", 0x0117 }, + { "ecaron", 0x011b }, + { "Ugrave", 0x00d9 }, + { "Thorn", 0x00de }, + { "eacute", 0x00e9 }, + { "edieresis", 0x00eb }, + { "dcaron", 0x010f }, + { "ccedilla", 0x00e7 }, + { "ccaron", 0x010d }, + { "cacute", 0x0107 }, + { "aogonek", 0x0105 }, + { "aring", 0x00e5 }, + { "atilde", 0x00e3 }, + { "abreve", 0x0103 }, + { "egrave", 0x00e8 }, + { "agrave", 0x00e0 }, + { "aacute", 0x00e1 }, + { "adieresis", 0x00e4 }, + { "Uogonek", 0x0172 }, + { "ugrave", 0x00f9 }, + { "uacute", 0x00fa }, + { "udieresis", 0x00fc }, + { "tcaron", 0x0165 }, + { "scommaaccent", 0x0219 }, + { "Zcaron", 0x017d }, + { "ecircumflex", 0x00ea }, + { "Ucircumflex", 0x00db }, + { "acircumflex", 0x00e2 }, + { "Zdotaccent", 0x017b }, + { "scaron", 0x0161 }, + { "Amacron", 0x0100 }, + { "sacute", 0x015b }, + { "Tcommaaccent", 0x0162 }, + { "Ydieresis", 0x0178 }, + { "thorn", 0x00fe }, + { "Emacron", 0x0112 }, + { "Ograve", 0x00d2 }, + { "Oacute", 0x00d3 }, + { "Odieresis", 0x00d6 }, + { "Ntilde", 0x00d1 }, + { "Ncaron", 0x0147 }, + { "Nacute", 0x0143 }, + { "Lcaron", 0x013d }, + { "Lacute", 0x0139 }, + { "Idotaccent", 0x0130 }, + { "racute", 0x0155 }, + { "Icircumflex", 0x00ce }, + { "ohungarumlaut", 0x0151 }, + { "otilde", 0x00f5 }, + { "Euro", 0x20ac }, + { "ocircumflex", 0x00f4 }, + { "onesuperior", 0x00b9 }, + { "twosuperior", 0x00b2 }, + { "threesuperior", 0x00b3 }, + { "Igrave", 0x00cc }, + { "Iacute", 0x00cd }, + { "Imacron", 0x012a }, + { "Iogonek", 0x012e }, + { "Idieresis", 0x00cf }, + { "Gbreve", 0x011e }, + { "Umacron", 0x016a }, + { "Kcommaaccent", 0x0136 }, + { "ograve", 0x00f2 }, + { "Scommaaccent", 0x0218 }, + { "Eogonek", 0x0118 }, + { "oacute", 0x00f3 }, + { "Edotaccent", 0x0116 }, + { "iogonek", 0x012f }, + { "gcommaaccent", 0x0123 }, + { "odieresis", 0x00f6 }, + { "ntilde", 0x00f1 }, + { "ncaron", 0x0148 }, + { "Ecaron", 0x011a }, + { "Ecircumflex", 0x00ca }, + { "scedilla", 0x015f }, + { "rcaron", 0x0159 }, + { "Egrave", 0x00c8 }, + { "Eacute", 0x00c9 }, + { "Gcommaaccent", 0x0122 }, + { "Rcommaaccent", 0x0156 }, + { "Edieresis", 0x00cb }, + { "nacute", 0x0144 }, + { "uogonek", 0x0173 }, + { "umacron", 0x016b }, + { "Dcaron", 0x010e }, + { "lcaron", 0x013e }, + { "Ccaron", 0x010c }, + { "Cacute", 0x0106 }, + { "Ccedilla", 0x00c7 }, + { "degree", 0x00b0 }, + { "Aogonek", 0x0104 }, + { "minus", 0x2212 }, + { "multiply", 0x00d7 }, + { "divide", 0x00f7 }, + { "Aring", 0x00c5 }, + { "trademark", 0x2122 }, + { "rcommaaccent", 0x0157 }, + { "lacute", 0x013a }, + { "omacron", 0x014d }, + { "Atilde", 0x00c3 }, + { "icircumflex", 0x00ee }, + { "igrave", 0x00ec }, + { "ncommaaccent", 0x0146 }, + { "lcommaaccent", 0x013c }, + { "plusminus", 0x00b1 }, + { "onehalf", 0x00bd }, + { "onequarter", 0x00bc }, + { "threequarters", 0x00be }, + { "iacute", 0x00ed }, + { "Abreve", 0x0102 }, + { "kcommaaccent", 0x0137 }, + { "Omacron", 0x014c }, + { "imacron", 0x012b }, + { "emacron", 0x0113 }, + { "amacron", 0x0101 }, + { "tcommaaccent", 0x0163 }, + { "ydieresis", 0x00ff }, + { "zdotaccent", 0x017c }, + { "zcaron", 0x017e }, + { "zacute", 0x017a }, + { "yacute", 0x00fd }, + { "uhungarumlaut", 0x0171 }, + { "eth", 0x00f0 }, + { "uring", 0x016f }, + { "Ocircumflex", 0x00d4 }, + { "commaaccent", 0xf6c3 }, + { "copyright", 0x00a9 }, + { "registered", 0x00ae }, + { "Acircumflex", 0x00c2 }, + { "idieresis", 0x00ef }, + { "lozenge", 0x25ca }, + { "Delta", 0x2206 }, + { "notequal", 0x2260 }, + { "radical", 0x221a }, + { "Agrave", 0x00c0 }, + { "Aacute", 0x00c1 }, + { "lessequal", 0x2264 }, + { "greaterequal", 0x2265 }, + { "logicalnot", 0x00ac }, + { "summation", 0x2211 }, + { "partialdiff", 0x2202 }, + { "Ncommaaccent", 0x0145 }, + { "dcroat", 0x0111 }, + { "brokenbar", 0x00a6 }, + { "Lcommaaccent", 0x013b }, + { "Adieresis", 0x00c4 }, + { "mu", 0x00b5 } +}; + +#define NR_GLYPHNAMES (sizeof(x49gp_glyphs) / sizeof(x49gp_glyphs[0])) + +#endif /* !(_X49GP_GLYPHNAME_H) */ diff --git a/include/.svn/text-base/list.h.svn-base b/include/.svn/text-base/list.h.svn-base new file mode 100644 index 0000000..ccf9148 --- /dev/null +++ b/include/.svn/text-base/list.h.svn-base @@ -0,0 +1,600 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include + +static inline void prefetch(const void *x) {;} + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifdef QEMU_OLD +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against removal of list entry. + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = rcu_dereference(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = rcu_dereference(pos->next)) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = rcu_dereference(n), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = rcu_dereference(list_entry(pos->member.next, \ + typeof(*pos), member))) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next; prefetch((pos)->next), (pos) != (head); \ + (pos) = rcu_dereference((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_for_each_rcu(pos, head) \ + for ((pos) = (head)->first; pos && ({ prefetch((pos)->next); 1; }); \ + (pos) = rcu_dereference((pos)->next)) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_head_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = rcu_dereference(pos->next)) + +#endif /* _LINUX_LIST_H */ diff --git a/include/.svn/text-base/s3c2410.h.svn-base b/include/.svn/text-base/s3c2410.h.svn-base new file mode 100644 index 0000000..53d1b58 --- /dev/null +++ b/include/.svn/text-base/s3c2410.h.svn-base @@ -0,0 +1,348 @@ +/* $Id: s3c2410.h,v 1.18 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_S3C2410_H +#define _X49GP_S3C2410_H 1 + +#include + +typedef struct { + const char *name; + uint32_t reset; + uint32_t *datap; +} s3c2410_offset_t; + +#define S3C2410_OFFSET(module, name, reset, data) \ + [S3C2410_ ## module ## _ ## name >> 2] = { #name, reset, &(data) } + +#define S3C2410_OFFSET_OK(p, offset) \ + ((((offset) >> 2) < (p)->nr_regs) && (p)->regs[(offset) >> 2].name) + +#define S3C2410_OFFSET_ENTRY(p, offset) &((p)->regs[(offset) >> 2]) + + +#define S3C2410_MAP_SIZE 0x00010000 + + +#define S3C2410_SRAM_BASE 0x40000000 +#define S3C2410_SRAM_SIZE 0x00001000 + +#define S3C2410_MEMC_BASE 0x48000000 + +#define S3C2410_MEMC_BWSCON 0x0000 +#define S3C2410_MEMC_BANKCON0 0x0004 +#define S3C2410_MEMC_BANKCON1 0x0008 +#define S3C2410_MEMC_BANKCON2 0x000c +#define S3C2410_MEMC_BANKCON3 0x0010 +#define S3C2410_MEMC_BANKCON4 0x0014 +#define S3C2410_MEMC_BANKCON5 0x0018 +#define S3C2410_MEMC_BANKCON6 0x001c +#define S3C2410_MEMC_BANKCON7 0x0020 +#define S3C2410_MEMC_REFRESH 0x0024 +#define S3C2410_MEMC_BANKSIZE 0x0028 +#define S3C2410_MEMC_MRSRB6 0x002c +#define S3C2410_MEMC_MRSRB7 0x0030 + +#define S3C2410_USBHOST_BASE 0x49000000 + +#define S3C2410_INTC_BASE 0x4a000000 + +#define S3C2410_INTC_SRCPND 0x0000 +#define S3C2410_INTC_INTMOD 0x0004 +#define S3C2410_INTC_INTMSK 0x0008 +#define S3C2410_INTC_PRIORITY 0x000c +#define S3C2410_INTC_INTPND 0x0010 +#define S3C2410_INTC_INTOFFSET 0x0014 +#define S3C2410_INTC_SUBSRCPND 0x0018 +#define S3C2410_INTC_INTSUBMSK 0x001c + +#define S3C2410_POWER_BASE 0x4c000000 + +#define S3C2410_POWER_LOCKTIME 0x0000 +#define S3C2410_POWER_MPLLCON 0x0004 +#define S3C2410_POWER_UPLLCON 0x0008 +#define S3C2410_POWER_CLKCON 0x000c +#define S3C2410_POWER_CLKSLOW 0x0010 +#define S3C2410_POWER_CLKDIVN 0x0014 + +#define S3C2410_LCD_BASE 0x4d000000 + +#define S3C2410_LCD_LCDCON1 0x0000 +#define S3C2410_LCD_LCDCON2 0x0004 +#define S3C2410_LCD_LCDCON3 0x0008 +#define S3C2410_LCD_LCDCON4 0x000c +#define S3C2410_LCD_LCDCON5 0x0010 +#define S3C2410_LCD_LCDSADDR1 0x0014 +#define S3C2410_LCD_LCDSADDR2 0x0018 +#define S3C2410_LCD_LCDSADDR3 0x001c +#define S3C2410_LCD_REDLUT 0x0020 +#define S3C2410_LCD_GREENLUT 0x0024 +#define S3C2410_LCD_BLUELUT 0x0028 +#define S3C2410_LCD_DITHMODE 0x004c +#define S3C2410_LCD_TPAL 0x0050 +#define S3C2410_LCD_LCDINTPND 0x0054 +#define S3C2410_LCD_LCDSRCPND 0x0058 +#define S3C2410_LCD_LCDINTMSK 0x005c +#define S3C2410_LCD_LPCSEL 0x0060 +#define S3C2410_LCD_UNKNOWN_68 0x0068 + +#define S3C2410_LCD_PALETTE_START 0x0400 +#define S3C2410_LCD_PALETTE_SIZE 0x0400 + +#define S3C2410_NAND_BASE 0x4e000000 + +#define S3C2410_NAND_NFCONF 0x0000 +#define S3C2410_NAND_NFCMD 0x0004 +#define S3C2410_NAND_NFADDR 0x0008 +#define S3C2410_NAND_NFDATA 0x000c +#define S3C2410_NAND_NFSTAT 0x0010 +#define S3C2410_NAND_NFECC 0x0014 + +#define S3C2410_UART0_BASE 0x50000000 +#define S3C2410_UART1_BASE 0x50004000 +#define S3C2410_UART2_BASE 0x50008000 + +#define S3C2410_UART0_ULCON 0x0000 +#define S3C2410_UART0_UCON 0x0004 +#define S3C2410_UART0_UFCON 0x0008 +#define S3C2410_UART0_UMCON 0x000c +#define S3C2410_UART0_UTRSTAT 0x0010 +#define S3C2410_UART0_UERSTAT 0x0014 +#define S3C2410_UART0_UFSTAT 0x0018 +#define S3C2410_UART0_UMSTAT 0x001c +#define S3C2410_UART0_UTXH 0x0020 +#define S3C2410_UART0_URXH 0x0024 +#define S3C2410_UART0_UBRDIV 0x0028 + +#define S3C2410_UART1_ULCON 0x0000 +#define S3C2410_UART1_UCON 0x0004 +#define S3C2410_UART1_UFCON 0x0008 +#define S3C2410_UART1_UMCON 0x000c +#define S3C2410_UART1_UTRSTAT 0x0010 +#define S3C2410_UART1_UERSTAT 0x0014 +#define S3C2410_UART1_UFSTAT 0x0018 +#define S3C2410_UART1_UMSTAT 0x001c +#define S3C2410_UART1_UTXH 0x0020 +#define S3C2410_UART1_URXH 0x0024 +#define S3C2410_UART1_UBRDIV 0x0028 + +#define S3C2410_UART2_ULCON 0x0000 +#define S3C2410_UART2_UCON 0x0004 +#define S3C2410_UART2_UFCON 0x0008 +#define S3C2410_UART2_UTRSTAT 0x0010 +#define S3C2410_UART2_UERSTAT 0x0014 +#define S3C2410_UART2_UFSTAT 0x0018 +#define S3C2410_UART2_UTXH 0x0020 +#define S3C2410_UART2_URXH 0x0024 +#define S3C2410_UART2_UBRDIV 0x0028 + +#define S3C2410_TIMER_BASE 0x51000000 + +#define S3C2410_TIMER_TCFG0 0x0000 +#define S3C2410_TIMER_TCFG1 0x0004 +#define S3C2410_TIMER_TCON 0x0008 +#define S3C2410_TIMER_TCNTB0 0x000c +#define S3C2410_TIMER_TCMPB0 0x0010 +#define S3C2410_TIMER_TCNTO0 0x0014 +#define S3C2410_TIMER_TCNTB1 0x0018 +#define S3C2410_TIMER_TCMPB1 0x001c +#define S3C2410_TIMER_TCNTO1 0x0020 +#define S3C2410_TIMER_TCNTB2 0x0024 +#define S3C2410_TIMER_TCMPB2 0x0028 +#define S3C2410_TIMER_TCNTO2 0x002c +#define S3C2410_TIMER_TCNTB3 0x0030 +#define S3C2410_TIMER_TCMPB3 0x0034 +#define S3C2410_TIMER_TCNTO3 0x0038 +#define S3C2410_TIMER_TCNTB4 0x003c +#define S3C2410_TIMER_TCNTO4 0x0040 + +#define S3C2410_USBDEV_BASE 0x52000000 + +#define S3C2410_USBDEV_FUNC_ADDR_REG 0x0140 +#define S3C2410_USBDEV_PWR_REG 0x0144 +#define S3C2410_USBDEV_EP_INT_REG 0x0148 +#define S3C2410_USBDEV_USB_INT_REG 0x0158 +#define S3C2410_USBDEV_EP_INT_EN_REG 0x015c +#define S3C2410_USBDEV_USB_INT_EN_REG 0x016c +#define S3C2410_USBDEV_FRAME_NUM1_REG 0x0170 +#define S3C2410_USBDEV_FRAME_NUM2_REG 0x0174 +#define S3C2410_USBDEV_INDEX_REG 0x0178 +#define S3C2410_USBDEV_EP0_FIFO_REG 0x01C0 +#define S3C2410_USBDEV_EP1_FIFO_REG 0x01C4 +#define S3C2410_USBDEV_EP2_FIFO_REG 0x01C8 +#define S3C2410_USBDEV_EP3_FIFO_REG 0x01CC +#define S3C2410_USBDEV_EP4_FIFO_REG 0x01D0 +#define S3C2410_USBDEV_EP1_DMA_CON 0x0200 +#define S3C2410_USBDEV_EP1_DMA_UNIT 0x0204 +#define S3C2410_USBDEV_EP1_DMA_FIFO 0x0208 +#define S3C2410_USBDEV_EP1_DMA_TTC_L 0x020C +#define S3C2410_USBDEV_EP1_DMA_TTC_M 0x0210 +#define S3C2410_USBDEV_EP1_DMA_TTC_H 0x0214 +#define S3C2410_USBDEV_EP2_DMA_CON 0x0218 +#define S3C2410_USBDEV_EP2_DMA_UNIT 0x021C +#define S3C2410_USBDEV_EP2_DMA_FIFO 0x0220 +#define S3C2410_USBDEV_EP2_DMA_TTC_L 0x0224 +#define S3C2410_USBDEV_EP2_DMA_TTC_M 0x0228 +#define S3C2410_USBDEV_EP2_DMA_TTC_H 0x022C +#define S3C2410_USBDEV_EP3_DMA_CON 0x0240 +#define S3C2410_USBDEV_EP3_DMA_UNIT 0x0244 +#define S3C2410_USBDEV_EP3_DMA_FIFO 0x0248 +#define S3C2410_USBDEV_EP3_DMA_TTC_L 0x024C +#define S3C2410_USBDEV_EP3_DMA_TTC_M 0x0250 +#define S3C2410_USBDEV_EP3_DMA_TTC_H 0x0254 +#define S3C2410_USBDEV_EP4_DMA_CON 0x0258 +#define S3C2410_USBDEV_EP4_DMA_UNIT 0x025C +#define S3C2410_USBDEV_EP4_DMA_FIFO 0x0260 +#define S3C2410_USBDEV_EP4_DMA_TTC_L 0x0264 +#define S3C2410_USBDEV_EP4_DMA_TTC_M 0x0268 +#define S3C2410_USBDEV_EP4_DMA_TTC_H 0x026C +#define S3C2410_USBDEV_MAXP_REG_WRONG 0x0180 +#define S3C2410_USBDEV_IN_CSR1_REG_EP0_CSR 0x0184 +#define S3C2410_USBDEV_IN_CSR2_REG 0x0188 +#define S3C2410_USBDEV_MAXP_REG 0x018c +#define S3C2410_USBDEV_OUT_CSR1_REG 0x0190 +#define S3C2410_USBDEV_OUT_CSR2_REG 0x0194 +#define S3C2410_USBDEV_OUT_FIFO_CNT1_REG 0x0198 +#define S3C2410_USBDEV_OUT_FIFO_CNT2_REG 0x019C + +#define S3C2410_WATCHDOG_BASE 0x53000000 + +#define S3C2410_WATCHDOG_WTCON 0x0000 +#define S3C2410_WATCHDOG_WTDAT 0x0004 +#define S3C2410_WATCHDOG_WTCNT 0x0008 + +#define S3C2410_IO_PORT_BASE 0x56000000 + +#define S3C2410_IO_PORT_GPACON 0x0000 +#define S3C2410_IO_PORT_GPADAT 0x0004 +#define S3C2410_IO_PORT_GPBCON 0x0010 +#define S3C2410_IO_PORT_GPBDAT 0x0014 +#define S3C2410_IO_PORT_GPBUP 0x0018 +#define S3C2410_IO_PORT_GPCCON 0x0020 +#define S3C2410_IO_PORT_GPCDAT 0x0024 +#define S3C2410_IO_PORT_GPCUP 0x0028 +#define S3C2410_IO_PORT_GPDCON 0x0030 +#define S3C2410_IO_PORT_GPDDAT 0x0034 +#define S3C2410_IO_PORT_GPDUP 0x0038 +#define S3C2410_IO_PORT_GPECON 0x0040 +#define S3C2410_IO_PORT_GPEDAT 0x0044 +#define S3C2410_IO_PORT_GPEUP 0x0048 +#define S3C2410_IO_PORT_GPFCON 0x0050 +#define S3C2410_IO_PORT_GPFDAT 0x0054 +#define S3C2410_IO_PORT_GPFUP 0x0058 +#define S3C2410_IO_PORT_GPGCON 0x0060 +#define S3C2410_IO_PORT_GPGDAT 0x0064 +#define S3C2410_IO_PORT_GPGUP 0x0068 +#define S3C2410_IO_PORT_GPHCON 0x0070 +#define S3C2410_IO_PORT_GPHDAT 0x0074 +#define S3C2410_IO_PORT_GPHUP 0x0078 +#define S3C2410_IO_PORT_MISCCR 0x0080 +#define S3C2410_IO_PORT_DCLKCON 0x0084 +#define S3C2410_IO_PORT_EXTINT0 0x0088 +#define S3C2410_IO_PORT_EXTINT1 0x008c +#define S3C2410_IO_PORT_EXTINT2 0x0090 +#define S3C2410_IO_PORT_EINTFLT0 0x0094 +#define S3C2410_IO_PORT_EINTFLT1 0x0098 +#define S3C2410_IO_PORT_EINTFLT2 0x009c +#define S3C2410_IO_PORT_EINTFLT3 0x00a0 +#define S3C2410_IO_PORT_EINTMASK 0x00a4 +#define S3C2410_IO_PORT_EINTPEND 0x00a8 +#define S3C2410_IO_PORT_GSTATUS0 0x00ac +#define S3C2410_IO_PORT_GSTATUS1 0x00b0 +#define S3C2410_IO_PORT_GSTATUS2 0x00b4 +#define S3C2410_IO_PORT_GSTATUS3 0x00b8 +#define S3C2410_IO_PORT_GSTATUS4 0x00bc + +#define S3C2410_RTC_BASE 0x57000000 + +#define S3C2410_RTC_RTCCON 0x0040 +#define S3C2410_RTC_TICNT 0x0044 +#define S3C2410_RTC_RTCALM 0x0050 +#define S3C2410_RTC_ALMSEC 0x0054 +#define S3C2410_RTC_ALMMIN 0x0058 +#define S3C2410_RTC_ALMHOUR 0x005c +#define S3C2410_RTC_ALMDATE 0x0060 +#define S3C2410_RTC_ALMMON 0x0064 +#define S3C2410_RTC_ALMYEAR 0x0068 +#define S3C2410_RTC_RTCRST 0x006c +#define S3C2410_RTC_BCDSEC 0x0070 +#define S3C2410_RTC_BCDMIN 0x0074 +#define S3C2410_RTC_BCDHOUR 0x0078 +#define S3C2410_RTC_BCDDATE 0x007c +#define S3C2410_RTC_BCDDAY 0x0080 +#define S3C2410_RTC_BCDMON 0x0084 +#define S3C2410_RTC_BCDYEAR 0x0088 + +#define S3C2410_ADC_BASE 0x58000000 + +#define S3C2410_ADC_ADCCON 0x0000 +#define S3C2410_ADC_ADCTSC 0x0004 +#define S3C2410_ADC_ADCDLY 0x0008 +#define S3C2410_ADC_ADCDAT0 0x000c +#define S3C2410_ADC_ADCDAT1 0x0010 + +#define S3C2410_SPI_BASE 0x59000000 + +#define S3C2410_SPI_SPICON0 0x0000 +#define S3C2410_SPI_SPISTA0 0x0004 +#define S3C2410_SPI_SPPIN0 0x0008 +#define S3C2410_SPI_SPPRE0 0x000c +#define S3C2410_SPI_SPTDAT0 0x0010 +#define S3C2410_SPI_SPRDAT0 0x0014 +#define S3C2410_SPI_SPICON1 0x0020 +#define S3C2410_SPI_SPISTA1 0x0024 +#define S3C2410_SPI_SPPIN1 0x0028 +#define S3C2410_SPI_SPPRE1 0x002c +#define S3C2410_SPI_SPTDAT1 0x0030 +#define S3C2410_SPI_SPRDAT1 0x0034 + +#define S3C2410_SDI_BASE 0x5a000000 + +#define S3C2410_SDI_SDICON 0x0000 +#define S3C2410_SDI_SDIPRE 0x0004 +#define S3C2410_SDI_SDICARG 0x0008 +#define S3C2410_SDI_SDICCON 0x000c +#define S3C2410_SDI_SDICSTA 0x0010 +#define S3C2410_SDI_SDIRSP0 0x0014 +#define S3C2410_SDI_SDIRSP1 0x0018 +#define S3C2410_SDI_SDIRSP2 0x001c +#define S3C2410_SDI_SDIRSP3 0x0020 +#define S3C2410_SDI_SDIDTIMER 0x0024 +#define S3C2410_SDI_SDIBSIZE 0x0028 +#define S3C2410_SDI_SDIDCON 0x002c +#define S3C2410_SDI_SDIDCNT 0x0030 +#define S3C2410_SDI_SDIDSTA 0x0034 +#define S3C2410_SDI_SDIFSTA 0x0038 +#define S3C2410_SDI_SDIDAT 0x003c +#define S3C2410_SDI_SDIIMSK 0x0040 + + +extern int x49gp_s3c2410_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_arm_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_mmu_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_sram_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_memc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_intc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_power_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_lcd_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_nand_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_uart_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_timer_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_usbdev_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_watchdog_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_io_port_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_rtc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_adc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_spi_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_sdi_init(x49gp_t *x49gp); + +extern void s3c2410_io_port_g_set_bit(x49gp_t *x49gp, int n, uint32_t set); +extern void s3c2410_io_port_f_set_bit(x49gp_t *x49gp, int n, uint32_t set); + +extern void x49gp_schedule_lcd_update(x49gp_t *x49gp); +extern void x49gp_lcd_update(x49gp_t *x49gp); + +extern unsigned long s3c2410_timer_next_interrupt(x49gp_t *x49gp); +extern unsigned long s3c2410_watchdog_next_interrupt(x49gp_t *x49gp); + +#endif /* !(_X49GP_S3C2410_H) */ diff --git a/include/.svn/text-base/s3c2410_intc.h.svn-base b/include/.svn/text-base/s3c2410_intc.h.svn-base new file mode 100644 index 0000000..b3c5ffd --- /dev/null +++ b/include/.svn/text-base/s3c2410_intc.h.svn-base @@ -0,0 +1,72 @@ +/* $Id: s3c2410_intc.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_S3C2410_INTC_H +#define _X49GP_S3C2410_INTC_H 1 + +#define INT_ADC 31 +#define INT_RTC 30 +#define INT_SPI1 29 +#define INT_UART0 28 +#define INT_IIC 27 +#define INT_USBH 26 +#define INT_USBD 25 +#define INT_UART1 23 +#define INT_SPI0 22 +#define INT_SDI 21 +#define INT_DMA3 20 +#define INT_DMA2 19 +#define INT_DMA1 18 +#define INT_DMA0 17 +#define INT_LCD 16 +#define INT_UART2 15 +#define INT_TIMER4 14 +#define INT_TIMER3 13 +#define INT_TIMER2 12 +#define INT_TIMER1 11 +#define INT_TIMER0 10 +#define INT_WDT 9 +#define INT_TICK 8 +#define nBATT_FLT 7 +#define EINT8_23 5 +#define EINT4_7 4 +#define EINT3 3 +#define EINT2 2 +#define EINT1 1 +#define EINT0 0 + +#define SUB_INT_ADC 10 +#define SUB_INT_TC 9 +#define SUB_INT_ERR2 8 +#define SUB_INT_TXD2 7 +#define SUB_INT_RXD2 6 +#define SUB_INT_ERR1 5 +#define SUB_INT_TXD1 4 +#define SUB_INT_RXD1 3 +#define SUB_INT_ERR0 2 +#define SUB_INT_TXD0 1 +#define SUB_INT_RXD0 0 + +#define ARB0_MODE (1 << 0) +#define ARB1_MODE (1 << 1) +#define ARB2_MODE (1 << 2) +#define ARB3_MODE (1 << 3) +#define ARB4_MODE (1 << 4) +#define ARB5_MODE (1 << 5) +#define ARB6_MODE (1 << 6) +#define ARB0_SEL_SHIFT 7 +#define ARB1_SEL_SHIFT 9 +#define ARB2_SEL_SHIFT 11 +#define ARB3_SEL_SHIFT 13 +#define ARB4_SEL_SHIFT 15 +#define ARB5_SEL_SHIFT 17 +#define ARB6_SEL_SHIFT 19 +#define ARBx_SEL_MASK 3 + +void s3c2410_intc_sub_assert(x49gp_t *x49gp, int sub_irq, int level); +void s3c2410_intc_sub_deassert(x49gp_t *x49gp, int sub_irq); + +void s3c2410_intc_assert(x49gp_t *x49gp, int irq, int level); +void s3c2410_intc_deassert(x49gp_t *x49gp, int irq); + +#endif /* !(_X49GP_S3C2410_INTC_H) */ diff --git a/include/.svn/text-base/s3c2410_mmu.h.svn-base b/include/.svn/text-base/s3c2410_mmu.h.svn-base new file mode 100644 index 0000000..561e2da --- /dev/null +++ b/include/.svn/text-base/s3c2410_mmu.h.svn-base @@ -0,0 +1,37 @@ +/* $Id: s3c2410_mmu.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_MMU_H +#define _S3C2410_MMU_H 1 + +#define S3C2410_MMU_TLB_SIZE 64 +#define S3C2410_MMU_TLB_MASK (S3C2410_MMU_TLB_SIZE - 1) + +typedef struct { + uint32_t mva; + uint32_t mask; + uint32_t pa; + uint32_t dac; + int valid; +} TLB_entry_t; + +typedef struct { + int victim; + int base; + int index0; + int index1; + unsigned long hit0; + unsigned long hit1; + unsigned long search; + unsigned long nsearch; + unsigned long walk; + TLB_entry_t data[S3C2410_MMU_TLB_SIZE]; +} TLB_t; + +typedef struct { + uint32_t MMUReg[16]; + TLB_t iTLB; + TLB_t dTLB; +} s3c2410_mmu_t; + +#endif /* !(_S3C2410_MMU_H) */ diff --git a/include/.svn/text-base/s3c2410_power.h.svn-base b/include/.svn/text-base/s3c2410_power.h.svn-base new file mode 100644 index 0000000..88c3a57 --- /dev/null +++ b/include/.svn/text-base/s3c2410_power.h.svn-base @@ -0,0 +1,28 @@ +/* $Id: s3c2410_power.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_POWER_H +#define _S3C2410_POWER_H 1 + +#define CLKCON_SPI 0x00040000 +#define CLKCON_IIS 0x00020000 +#define CLKCON_IIC 0x00010000 +#define CLKCON_ADC 0x00008000 +#define CLKCON_RTC 0x00004000 +#define CLKCON_GPIO 0x00002000 +#define CLKCON_UART2 0x00001000 +#define CLKCON_UART1 0x00000800 +#define CLKCON_UART0 0x00000400 +#define CLKCON_SDI 0x00000200 +#define CLKCON_TIMER 0x00000100 +#define CLKCON_USBD 0x00000080 +#define CLKCON_USBH 0x00000040 +#define CLKCON_LCD 0x00000020 +#define CLKCON_NAND 0x00000010 +#define CLKCON_POWER_OFF 0x00000008 +#define CLKCON_IDLE 0x00000004 +#define CLKCON_SM_BIT 0x00000001 + +extern int s3c2410_idle; + +#endif /* !(_S3C2410_POWER_H) */ diff --git a/include/.svn/text-base/s3c2410_timer.h.svn-base b/include/.svn/text-base/s3c2410_timer.h.svn-base new file mode 100644 index 0000000..5fcfe25 --- /dev/null +++ b/include/.svn/text-base/s3c2410_timer.h.svn-base @@ -0,0 +1,48 @@ +/* $Id: s3c2410_timer.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_TIMER_H +#define _S3C2410_TIMER_H 1 + +#include + +#define TCFG0_DEAD_SHIFT 16 +#define TCFG0_DEAD_MASK 0xff +#define TCFG0_PRE1_SHIFT 8 +#define TCFG0_PRE0_SHIFT 0 +#define TCFG0_PREx_MASK 0xff + +#define TCFG1_DMA_SHIFT 20 +#define TCFG1_DMA_MASK 0x0f +#define TCFG1_MUX4_SHIFT 16 +#define TCFG1_MUX3_SHIFT 12 +#define TCFG1_MUX2_SHIFT 8 +#define TCFG1_MUX1_SHIFT 4 +#define TCFG1_MUX0_SHIFT 0 +#define TCFG1_MUXx_MASK 0x0f + +#define TCON_TIMER4_RELOAD 0x00400000 +#define TCON_TIMER4_UPDATE 0x00200000 +#define TCON_TIMER4_START 0x00100000 +#define TCON_TIMER3_RELOAD 0x00080000 +#define TCON_TIMER3_INVERT 0x00040000 +#define TCON_TIMER3_UPDATE 0x00020000 +#define TCON_TIMER3_START 0x00010000 +#define TCON_TIMER2_RELOAD 0x00008000 +#define TCON_TIMER2_INVERT 0x00004000 +#define TCON_TIMER2_UPDATE 0x00002000 +#define TCON_TIMER2_START 0x00001000 +#define TCON_TIMER1_RELOAD 0x00000800 +#define TCON_TIMER1_INVERT 0x00000400 +#define TCON_TIMER1_UPDATE 0x00000200 +#define TCON_TIMER1_START 0x00000100 +#define TCON_TIMER0_DEADZONE 0x00000010 +#define TCON_TIMER0_RELOAD 0x00000008 +#define TCON_TIMER0_INVERT 0x00000004 +#define TCON_TIMER0_UPDATE 0x00000002 +#define TCON_TIMER0_START 0x00000001 + +void s3c2410_run_timers(x49gp_t *x49gp); +clock_t s3c2410_next_timer(x49gp_t *x49gp); + +#endif /* !(_S3C2410_TIMER_H) */ diff --git a/include/.svn/text-base/saturn.h.svn-base b/include/.svn/text-base/saturn.h.svn-base new file mode 100644 index 0000000..b1102ff --- /dev/null +++ b/include/.svn/text-base/saturn.h.svn-base @@ -0,0 +1,43 @@ +/* $Id: saturn.h,v 1.1 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef SATURN_H +#define SATURN_H 1 + +#define NB_RSTK 8 + +typedef uint64_t saturn_reg_t; + +typedef struct { + uint32_t read_map[256 + 1]; + uint32_t write_map[256 + 1]; + uint8_t top_map[256 + 1 + 3]; + saturn_reg_t A; + saturn_reg_t B; + saturn_reg_t C; + saturn_reg_t D; + saturn_reg_t R0; + saturn_reg_t R1; + saturn_reg_t R2; + saturn_reg_t R3; + saturn_reg_t R4; + uint32_t D0; + uint32_t D1; + uint32_t P, P4, P4_32; + uint32_t ST; + uint32_t HST; + uint32_t carry; + int dec; + uint32_t RSTK[NB_RSTK]; + uint32_t RSTK_i; + uint32_t REG_FIELD[32]; + uint32_t FIELD_START[32]; + uint32_t FIELD_LENGTH[32]; +} saturn_cpu_t; + +#define SAT_RPLTOP 0x8076b +#define SAT_RSKTOP 0x806f3 /* RETTOP */ +#define SAT_DSKTOP 0x806f8 +#define SAT_EDITLINE 0x806fd + +#endif /* !(SATURN_H) */ diff --git a/include/.svn/text-base/symbol.h.svn-base b/include/.svn/text-base/symbol.h.svn-base new file mode 100644 index 0000000..53174f6 --- /dev/null +++ b/include/.svn/text-base/symbol.h.svn-base @@ -0,0 +1,68 @@ +/* $Id: symbol.h,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_SYMBOL_H +#define _X49GP_SYMBOL_H 1 + +#include + +typedef struct { + const cairo_path_data_t *data; + int num_data; +} symbol_path_t; + +typedef struct { + double x_advance; + double y_advance; + double llx; + double lly; + double urx; + double ury; + double prescale; + double postscale; + const symbol_path_t *path; +} x49gp_symbol_t; + +#define SYMBOL_MOVE_TO(x, y) \ + { header: { CAIRO_PATH_MOVE_TO, 2 } }, \ + { point: { x, y } } + +#define SYMBOL_LINE_TO(x, y) \ + { header: { CAIRO_PATH_LINE_TO, 2 } }, \ + { point: { x, y } } + +#define SYMBOL_CURVE_TO(x1, y1, x2, y2, x3, y3) \ + { header: { CAIRO_PATH_CURVE_TO, 4 } }, \ + { point: { x1, y1 } }, \ + { point: { x2, y2 } }, \ + { point: { x3, y3 } } + +#define SYMBOL_CLOSE_PATH() \ + { header: { CAIRO_PATH_CLOSE_PATH, 1 } } + +#define SYMBOL(name, x_advance, y_advance, llx, lly, urx, ury) \ +static const symbol_path_t symbol_##name##_path = \ +{ \ + symbol_##name##_path_data, \ + sizeof(symbol_##name##_path_data) / sizeof(cairo_path_data_t) \ +}; \ + \ +static const x49gp_symbol_t symbol_##name = \ +{ \ + x_advance, y_advance, llx, lly, urx, ury, 1.0, 1.0, \ + &symbol_##name##_path \ +} + +#define CONTROL(name, x_advance, y_advance, prescale, postscale) \ +static const x49gp_symbol_t symbol_##name = \ +{ \ + x_advance, y_advance, 0.0, 0.0, 0.0, 0.0, \ + prescale, postscale, NULL \ +} + +int symbol_lookup_glyph_by_name(const char *name, int namelen, gunichar *); + +const x49gp_symbol_t *symbol_get_by_name(const char *name); +const x49gp_symbol_t *symbol_get_by_glyph(gunichar glyph); + +#endif /* !(_X49GP_SYMBOL_H) */ diff --git a/include/.svn/text-base/x49gp.h.svn-base b/include/.svn/text-base/x49gp.h.svn-base new file mode 100644 index 0000000..6739281 --- /dev/null +++ b/include/.svn/text-base/x49gp.h.svn-base @@ -0,0 +1,144 @@ +/* $Id: x49gp.h,v 1.15 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_H +#define _X49GP_H + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +/* LD TEMPO HACK */ +#ifndef QEMU_OLD +extern uint8_t *phys_ram_base; +extern int phys_ram_size; +#endif + +typedef enum { + X49GP_ARM_RUN = 0, + X49GP_ARM_SLEEP, + X49GP_ARM_OFF +} x49gp_arm_idle_t; + +typedef enum { + X49GP_RESET_POWER_ON = 0, + X49GP_RESET_POWER_OFF, + X49GP_RESET_WATCHDOG +} x49gp_reset_t; + +struct __x49gp_module_s__; +typedef struct __x49gp_module_s__ x49gp_module_t; + +struct __x49gp_module_s__ { + const char *name; + + int (*init) (x49gp_module_t *); + int (*exit) (x49gp_module_t *); + + int (*reset) (x49gp_module_t *, x49gp_reset_t); + + int (*load) (x49gp_module_t *, GKeyFile *); + int (*save) (x49gp_module_t *, GKeyFile *); + + void *user_data; + + x49gp_t *x49gp; + struct list_head list; +}; + + +struct __x49gp_s__ { + CPUARMState *env; + + struct list_head modules; + + void *s3c2410_lcd; + void *s3c2410_timer; + void *s3c2410_watchdog; + void *s3c2410_intc; + void *s3c2410_io_port; + + void *timer; + uint8_t *sram; + + uint32_t MCLK; + uint32_t UCLK; + + uint32_t FCLK; + uint32_t HCLK; + uint32_t PCLK; + int PCLK_ratio; + + clock_t clk_tck; + unsigned long emulator_fclk; + + unsigned char keybycol[8]; + unsigned char keybyrow[8]; + + x49gp_timer_t *gtk_timer; + x49gp_timer_t *lcd_timer; + + x49gp_arm_idle_t arm_idle; + int arm_exit; + + x49gp_ui_t *ui; + + GKeyFile *config; + const char *progname; +}; + +extern void x49gp_set_idle(x49gp_t *, x49gp_arm_idle_t idle); + +extern int x49gp_module_init(x49gp_t *x49gp, const char *name, + int (*init)(x49gp_module_t *), + int (*exit)(x49gp_module_t *), + int (*reset)(x49gp_module_t *, x49gp_reset_t), + int (*load)(x49gp_module_t *, GKeyFile *), + int (*save)(x49gp_module_t *, GKeyFile *), + void *user_data, x49gp_module_t **module); + +extern int x49gp_module_register(x49gp_module_t *module); +extern int x49gp_module_unregister(x49gp_module_t *module); + +extern char *x49gp_module_get_filename(x49gp_module_t *module, GKeyFile *, + const char *key); +extern int x49gp_module_get_int(x49gp_module_t *module, GKeyFile *, + const char *, int, int *); +extern int x49gp_module_set_int(x49gp_module_t *module, GKeyFile *, + const char *, int); +extern int x49gp_module_get_uint(x49gp_module_t *module, GKeyFile *, + const char *, + unsigned int, unsigned int *); +extern int x49gp_module_set_uint(x49gp_module_t *module, GKeyFile *, + const char *, unsigned int); +extern int x49gp_module_get_u32(x49gp_module_t *module, GKeyFile *, + const char *, uint32_t, uint32_t *); +extern int x49gp_module_set_u32(x49gp_module_t *module, GKeyFile *, + const char *, uint32_t); +extern int x49gp_module_get_u64(x49gp_module_t *module, GKeyFile *, + const char *, uint64_t, uint64_t *); +extern int x49gp_module_set_u64(x49gp_module_t *module, GKeyFile *, + const char *, uint64_t); +extern int x49gp_module_get_string(x49gp_module_t *module, GKeyFile *, + const char *, char *, char **); + +extern int x49gp_modules_init(x49gp_t *); +extern int x49gp_modules_exit(x49gp_t *); +extern int x49gp_modules_reset(x49gp_t *, x49gp_reset_t); +extern int x49gp_modules_load(x49gp_t *, const char *); +extern int x49gp_modules_save(x49gp_t *, const char *); + +extern int x49gp_flash_init(x49gp_t *); +extern int x49gp_sram_init(x49gp_t *); + +#endif /* !(_X49GP_H) */ diff --git a/include/.svn/text-base/x49gp_timer.h.svn-base b/include/.svn/text-base/x49gp_timer.h.svn-base new file mode 100644 index 0000000..e5acdcb --- /dev/null +++ b/include/.svn/text-base/x49gp_timer.h.svn-base @@ -0,0 +1,32 @@ +/* $Id: x49gp_timer.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_TIMER_H +#define _X49GP_TIMER_H 1 + +#include +#include + +#define X49GP_TIMER_VIRTUAL 0 +#define X49GP_TIMER_REALTIME 1 + +int64_t x49gp_get_clock(void); + +typedef void (*x49gp_timer_cb_t) (void *); +typedef struct x49gp_timer_s x49gp_timer_t; + +x49gp_timer_t *x49gp_new_timer(long type, x49gp_timer_cb_t, void *user_data); +void x49gp_free_timer(x49gp_timer_t *); + +void x49gp_mod_timer(x49gp_timer_t *, int64_t expires); +void x49gp_del_timer(x49gp_timer_t *); +int x49gp_timer_pending(x49gp_timer_t *); +int64_t x49gp_timer_expires(x49gp_timer_t *); + +#define X49GP_GTK_REFRESH_INTERVAL 30000LL +#define X49GP_LCD_REFRESH_INTERVAL 50000LL + +int x49gp_main_loop(x49gp_t *); +int x49gp_timer_init(x49gp_t *); + +#endif /* !(_X49GP_TIMER_H) */ diff --git a/include/.svn/text-base/x49gp_types.h.svn-base b/include/.svn/text-base/x49gp_types.h.svn-base new file mode 100644 index 0000000..f6b52d7 --- /dev/null +++ b/include/.svn/text-base/x49gp_types.h.svn-base @@ -0,0 +1,23 @@ +/* $Id: x49gp_types.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_TYPES_H +#define _X49GP_TYPES_H 1 + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +struct __x49gp_s__; +typedef struct __x49gp_s__ x49gp_t; + +struct __x49gp_ui_s__; +typedef struct __x49gp_ui_s__ x49gp_ui_t; + +#endif /* !(_X49GP_TYPES_H) */ diff --git a/include/.svn/text-base/x49gp_ui.h.svn-base b/include/.svn/text-base/x49gp_ui.h.svn-base new file mode 100644 index 0000000..e019b78 --- /dev/null +++ b/include/.svn/text-base/x49gp_ui.h.svn-base @@ -0,0 +1,125 @@ +/* $Id: x49gp_ui.h,v 1.14 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_UI_H +#define _X49GP_UI_H 1 + +#include + +typedef enum { + UI_COLOR_BLACK = 0, + UI_COLOR_WHITE, + UI_COLOR_YELLOW, + UI_COLOR_RED, + UI_COLOR_GREEN, + UI_COLOR_SILVER, + UI_COLOR_ORANGE, + UI_COLOR_BLUE, + UI_COLOR_MAX +} x49gp_ui_color_t; + +typedef enum { + UI_SHAPE_BUTTON_TINY = 0, + UI_SHAPE_BUTTON_SMALL, + UI_SHAPE_BUTTON_NORMAL, + UI_SHAPE_BUTTON_LARGE, + UI_SHAPE_BUTTON_ROUND, + UI_SHAPE_MAX +} x49gp_ui_shape_t; + +typedef enum { + UI_LAYOUT_LEFT = 0, + UI_LAYOUT_LEFT_NO_SPACE, + UI_LAYOUT_BELOW, + UI_LAYOUT_MAX +} x49gp_ui_layout_t; + +typedef enum { + UI_CALCULATOR_HP49GP = 0, + UI_CALCULATOR_HP50G +} x49gp_ui_calculator_t; + + +typedef struct { + const char *label; + const char *letter; + const char *left; + const char *right; + const char *below; + x49gp_ui_color_t color; + double font_size; + cairo_font_weight_t font_weight; + x49gp_ui_shape_t shape; + double letter_size; + x49gp_ui_layout_t layout; + int x; + int y; + int width; + int height; + int column; + int row; + unsigned char columnbit; + unsigned char rowbit; + int eint; +} x49gp_ui_key_t; + +typedef struct { + x49gp_t *x49gp; + const x49gp_ui_key_t *key; + GtkWidget *button; + GtkWidget *label; + GtkWidget *box; + GdkPixmap *pixmap; + gboolean down; + gboolean hold; +} x49gp_ui_button_t; + +struct __x49gp_ui_s__ { + GtkWidget *window; + GtkWidget *fixed; + + GdkPixbuf *bg_pixbuf; + GdkPixmap *bg_pixmap; + GtkWidget *background; + + GdkColor colors[UI_COLOR_MAX]; + GdkBitmap *shapes[UI_SHAPE_MAX]; + + x49gp_ui_calculator_t calculator; + + x49gp_ui_button_t *buttons; + unsigned int nr_buttons; + + GtkWidget *lcd_canvas; + GdkPixmap *lcd_pixmap; + + GdkGC *ann_left_gc; + GdkGC *ann_right_gc; + GdkGC *ann_alpha_gc; + GdkGC *ann_battery_gc; + GdkGC *ann_busy_gc; + GdkGC *ann_io_gc; + + GdkBitmap *ann_left; + GdkBitmap *ann_right; + GdkBitmap *ann_alpha; + GdkBitmap *ann_battery; + GdkBitmap *ann_busy; + GdkBitmap *ann_io; + + gint width; + gint height; + + gint kb_x_offset; + gint kb_y_offset; + + gint lcd_x_offset; + gint lcd_y_offset; + gint lcd_width; + gint lcd_height; + gint lcd_top_margin; +}; + +int x49gp_ui_init(x49gp_t *x49gp); + +#endif /* !(_X49GP_UI_H) */ diff --git a/include/CVS/.svn/all-wcprops b/include/CVS/.svn/all-wcprops new file mode 100644 index 0000000..71d6180 --- /dev/null +++ b/include/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 36 +/p/x49gp/code/!svn/ver/1/include/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/include/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/include/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/include/CVS/Entries +END diff --git a/include/CVS/.svn/entries b/include/CVS/.svn/entries new file mode 100644 index 0000000..613a7a3 --- /dev/null +++ b/include/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/include/CVS +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +Repository +file + + + + +2013-08-23T00:54:46.000000Z +787f1f54d99013d8c01d85d015aa21ed +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +14 + +Root +file + + + + +2013-08-23T00:54:46.000000Z +f51b768066a9e7d88829b19678326fcd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +60 + +Entries +file + + + + +2013-08-23T00:54:46.000000Z +078400b504794b71bc803fc0f7dd0736 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +748 + diff --git a/include/CVS/.svn/text-base/Entries.svn-base b/include/CVS/.svn/text-base/Entries.svn-base new file mode 100644 index 0000000..9e08e9f --- /dev/null +++ b/include/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,18 @@ +/bitmap_font.h/1.5/Thu Dec 11 12:18:17 2008// +/bitmaps.h/1.9/Thu Dec 11 12:18:17 2008// +/block.h/1.1/Thu Dec 11 12:18:17 2008// +/byteorder.h/1.5/Thu Dec 11 12:18:17 2008// +/glyphname.h/1.3/Thu Dec 11 12:18:17 2008// +/list.h/1.5/Thu Dec 11 12:18:17 2008// +/s3c2410.h/1.18/Thu Dec 11 12:18:17 2008// +/s3c2410_intc.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_mmu.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_power.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_timer.h/1.3/Thu Dec 11 12:18:17 2008// +/saturn.h/1.1/Thu Dec 11 12:18:17 2008// +/symbol.h/1.4/Thu Dec 11 12:18:17 2008// +/x49gp.h/1.15/Thu Dec 11 12:18:17 2008// +/x49gp_timer.h/1.3/Thu Dec 11 12:18:17 2008// +/x49gp_types.h/1.5/Thu Dec 11 12:18:17 2008// +/x49gp_ui.h/1.14/Thu Dec 11 12:18:17 2008// +D diff --git a/include/CVS/.svn/text-base/Repository.svn-base b/include/CVS/.svn/text-base/Repository.svn-base new file mode 100644 index 0000000..9500df1 --- /dev/null +++ b/include/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +x49gp/include diff --git a/include/CVS/.svn/text-base/Root.svn-base b/include/CVS/.svn/text-base/Root.svn-base new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/include/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/include/CVS/Entries b/include/CVS/Entries new file mode 100644 index 0000000..9e08e9f --- /dev/null +++ b/include/CVS/Entries @@ -0,0 +1,18 @@ +/bitmap_font.h/1.5/Thu Dec 11 12:18:17 2008// +/bitmaps.h/1.9/Thu Dec 11 12:18:17 2008// +/block.h/1.1/Thu Dec 11 12:18:17 2008// +/byteorder.h/1.5/Thu Dec 11 12:18:17 2008// +/glyphname.h/1.3/Thu Dec 11 12:18:17 2008// +/list.h/1.5/Thu Dec 11 12:18:17 2008// +/s3c2410.h/1.18/Thu Dec 11 12:18:17 2008// +/s3c2410_intc.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_mmu.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_power.h/1.3/Thu Dec 11 12:18:17 2008// +/s3c2410_timer.h/1.3/Thu Dec 11 12:18:17 2008// +/saturn.h/1.1/Thu Dec 11 12:18:17 2008// +/symbol.h/1.4/Thu Dec 11 12:18:17 2008// +/x49gp.h/1.15/Thu Dec 11 12:18:17 2008// +/x49gp_timer.h/1.3/Thu Dec 11 12:18:17 2008// +/x49gp_types.h/1.5/Thu Dec 11 12:18:17 2008// +/x49gp_ui.h/1.14/Thu Dec 11 12:18:17 2008// +D diff --git a/include/CVS/Repository b/include/CVS/Repository new file mode 100644 index 0000000..9500df1 --- /dev/null +++ b/include/CVS/Repository @@ -0,0 +1 @@ +x49gp/include diff --git a/include/CVS/Root b/include/CVS/Root new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/include/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/include/bitmap_font.h b/include/bitmap_font.h new file mode 100644 index 0000000..ef99d6f --- /dev/null +++ b/include/bitmap_font.h @@ -0,0 +1,37 @@ +/* $Id: bitmap_font.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BITMAP_FONT_H +#define _X49GP_BITMAP_FONT_H 1 + +typedef struct { + const char *name; + int width; + int kern; + int ascent; + int descent; + const unsigned char *bits; +} bitmap_glyph_t; + +typedef struct { + int ascent; + int descent; + bitmap_glyph_t glyphs[]; +} bitmap_font_t; + +#define GLYPH(font, name) \ + { \ + #name, \ + font##_##name##_width - font##_##name##_x_hot, \ + -font##_##name##_x_hot, \ + font##_##name##_y_hot + 1, \ + font##_##name##_y_hot + 1 - font##_##name##_height, \ + font##_##name##_bits \ + } + +#define SPACE(name, width, kern) \ + { name, width, kern, 0, 0, NULL } + +extern const bitmap_font_t tiny_font; + +#endif /* !(_X49GP_BITMAP_FONT_H) */ diff --git a/include/bitmaps.h b/include/bitmaps.h new file mode 100644 index 0000000..de8e25d --- /dev/null +++ b/include/bitmaps.h @@ -0,0 +1,21 @@ +/* $Id: bitmaps.h,v 1.9 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BITMAPS_H +#define _X49GP_BITMAPS_H 1 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif /* !(_X49GP_BITMAPS_H) */ diff --git a/include/block.h b/include/block.h new file mode 100644 index 0000000..e4c285a --- /dev/null +++ b/include/block.h @@ -0,0 +1,187 @@ +/* $Id: block.h,v 1.1 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef BLOCK_H +#define BLOCK_H 1 + +#include + +#define BDRV_O_RDONLY 0x0000 +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_ACCESS 0x0003 +#define BDRV_O_CREAT 0x0004 /* create an empty file */ +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save + writes in a snapshot */ +#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to + use a disk image format on top of + it (default for + bdrv_file_open()) */ + +#ifdef QEMU_OLD +typedef struct BlockDriverState BlockDriverState; +#endif +typedef struct BlockDriver BlockDriver; +typedef struct SnapshotInfo QEMUSnapshotInfo; +typedef struct BlockDriverInfo BlockDriverInfo; +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_host_device; +extern BlockDriver bdrv_qcow; +extern BlockDriver bdrv_vvfat; + +void bdrv_init(void); +int bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_delete(BlockDriverState *bs); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags); + +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); + +#ifdef QEMU_OLD +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + int (*bdrv_make_empty)(BlockDriverState *bs); + /* aio */ + BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb); + int aiocb_size; + + const char *protocol_name; + int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count); + int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count); + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int64_t (*bdrv_getlength)(BlockDriverState *bs); + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + + int (*bdrv_snapshot_create)(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); + int (*bdrv_snapshot_goto)(BlockDriverState *bs, + const char *snapshot_id); + int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); + int (*bdrv_snapshot_list)(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag); + int (*bdrv_set_locked)(BlockDriverState *bs, int locked); + + BlockDriverAIOCB *free_aiocb; + struct BlockDriver *next; +}; + +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + int media_changed; + + BlockDriverState *backing_hd; +// /* async read/write emulation */ +// +// void *sync_aiocb; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs, translation; + int type; + char device_name[32]; + BlockDriverState *next; +}; + +void *qemu_malloc(size_t size); +void *qemu_mallocz(size_t size); +void qemu_free(void *ptr); + +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +#endif /* QEMU_OLD */ + +#ifndef QEMU_OLD +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); +void bdrv_flush(BlockDriverState *bs); + +/* timers */ + +typedef struct QEMUClock QEMUClock; +typedef void QEMUTimerCB(void *opaque); + +/* The real time clock should be used only for stuff which does not + change the virtual machine state, as it is run even if the virtual + machine is stopped. The real time clock has a frequency of 1000 + Hz. */ +extern QEMUClock *rt_clock; + +int64_t qemu_get_clock(QEMUClock *clock); + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); +void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +int qemu_timer_pending(QEMUTimer *ts); + +extern int64_t ticks_per_sec; + +struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; +}; + +#endif + +#endif /* !(BLOCK_H) */ diff --git a/include/block_int.h b/include/block_int.h new file mode 100644 index 0000000..581679a --- /dev/null +++ b/include/block_int.h @@ -0,0 +1,104 @@ +/* + * QEMU System Emulator block driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCK_INT_H +#define BLOCK_INT_H + +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + int (*bdrv_make_empty)(BlockDriverState *bs); + + const char *protocol_name; + int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, + uint8_t *buf, int count); + int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, + const uint8_t *buf, int count); + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int64_t (*bdrv_getlength)(BlockDriverState *bs); + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag); + int (*bdrv_set_locked)(BlockDriverState *bs, int locked); + + struct BlockDriver *next; +}; + +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + int media_changed; + + BlockDriverState *backing_hd; + /* async read/write emulation */ + + void *sync_aiocb; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs, translation; + int type; + char device_name[32]; + BlockDriverState *next; +}; + +void get_tmp_filename(char *filename, int size); + +#endif /* BLOCK_INT_H */ diff --git a/include/byteorder.h b/include/byteorder.h new file mode 100644 index 0000000..72fb035 --- /dev/null +++ b/include/byteorder.h @@ -0,0 +1,91 @@ +/* $Id: byteorder.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_BYTEORDER_H +#define _X49GP_BYTEORDER_H 1 + +#include + +static __inline__ uint16_t swab16(uint16_t x) +{ + return ((x & 0xff00) >> 8) | + ((x & 0x00ff) << 8); +} + +static __inline__ uint32_t swab32(uint32_t x) +{ + return ((x & 0xff000000) >> 24) | + ((x & 0x00ff0000) >> 8) | + ((x & 0x0000ff00) << 8) | + ((x & 0x000000ff) << 24); +} + +#ifdef __sparc__ + +#define ASI_PL 0x88 /* Primary, implicit, little endian. */ + +static __inline__ uint16_t __load_le16(const uint16_t *p) +{ + uint16_t x; + + __asm__ __volatile__ ("lduha [%1] %2, %0" + : "=r" (x) + : "r" (p), "i" (ASI_PL)); + return x; +} + +static __inline__ uint32_t __load_le32(const uint32_t *p) +{ + uint32_t x; + + __asm__ __volatile__ ("lduwa [%1] %2, %0" + : "=r" (x) + : "r" (p), "i" (ASI_PL)); + return x; +} + +static __inline__ void __store_le16(uint16_t *p, uint16_t x) +{ + __asm__ __volatile__ ("stha %0, [%1] %2" + : /* no outputs */ + : "r" (x), "r" (p), "i" (ASI_PL)); +} + +static __inline__ void __store_le32(uint32_t *p, uint32_t x) +{ + __asm__ __volatile__ ("stwa %0, [%1] %2" + : /* no outputs */ + : "r" (x), "r" (p), "i" (ASI_PL)); +} + +#endif /* __sparc__ */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +#define load_le16(p) (*(p)) +#define store_le16(p, x) (*(p) = (x)) +#define load_le32(p) (*(p)) +#define store_le32(p, x) (*(p) = (x)) + +#elif __BYTE_ORDER == __BIG_ENDIAN + +#define le16_to_cpu(x) swab16(x) +#define cpu_to_le16(x) swab16(x) +#define le32_to_cpu(x) swab32(x) +#define cpu_to_le32(x) swab32(x) + +#define load_le16(p) __load_le16(p) +#define store_le16(p, x) __store_le16(p, x) +#define load_le32(p) __load_le32(p) +#define store_le32(p, x) __store_le32(p, x) + +#else +#error "Cannot determine host byteorder" +#endif + +#endif /* !(_X49GP_BYTEORDER_H) */ diff --git a/include/glyphname.h b/include/glyphname.h new file mode 100644 index 0000000..787d8e9 --- /dev/null +++ b/include/glyphname.h @@ -0,0 +1,238 @@ +/* $Id: glyphname.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_GLYPHNAME_H +#define _X49GP_GLYPHNAME_H 1 + +typedef struct { + const char *name; + gunichar unichar; +} x49gp_glyph_t; + +static const x49gp_glyph_t x49gp_glyphs[] = +{ + { "exclamdown", 0x00a1 }, + { "cent", 0x00a2 }, + { "sterling", 0x00a3 }, + { "fraction", 0x2044 }, + { "yen", 0x00a5 }, + { "florin", 0x0192 }, + { "section", 0x00a7 }, + { "currency", 0x00a4 }, + { "quotesingle", 0x0027 }, + { "quotedblleft", 0x201c }, + { "guillemotleft", 0x00ab }, + { "guilsinglleft", 0x2039 }, + { "guilsinglright", 0x203a }, + { "fi", 0xfb01 }, + { "fl", 0xfb02 }, + { "endash", 0x2013 }, + { "dagger", 0x2020 }, + { "daggerdbl", 0x2021 }, + { "periodcentered", 0x00b7 }, + { "paragraph", 0x00b6 }, + { "bullet", 0x2022 }, + { "quotesinglbase", 0x201a }, + { "quotedblbase", 0x201e }, + { "quotedblright", 0x201d }, + { "guillemotright", 0x00bb }, + { "ellipsis", 0x2026 }, + { "perthousand", 0x2030 }, + { "questiondown", 0x00bf }, + { "grave", 0x0060 }, + { "acute", 0x00b4 }, + { "circumflex", 0x02c6 }, + { "tilde", 0x02dc }, + { "macron", 0x00af }, + { "breve", 0x02d8 }, + { "dotaccent", 0x02d9 }, + { "dieresis", 0x00a8 }, + { "ring", 0x02da }, + { "cedilla", 0x00b8 }, + { "hungarumlaut", 0x02dd }, + { "ogonek", 0x02db }, + { "caron", 0x02c7 }, + { "emdash", 0x2014 }, + { "AE", 0x00c6 }, + { "ordfeminine", 0x00aa }, + { "Lslash", 0x0141 }, + { "Oslash", 0x00d8 }, + { "OE", 0x0152 }, + { "ordmasculine", 0x00ba }, + { "ae", 0x00e6 }, + { "dotlessi", 0x0131 }, + { "lslash", 0x0142 }, + { "oslash", 0x00f8 }, + { "oe", 0x0153 }, + { "germandbls", 0x00df }, + { "Udieresis", 0x00dc }, + { "Uacute", 0x00da }, + { "Scedilla", 0x015e }, + { "Tcaron", 0x0164 }, + { "Scaron", 0x0160 }, + { "Rcaron", 0x0158 }, + { "Racute", 0x0154 }, + { "Sacute", 0x015a }, + { "Otilde", 0x00d5 }, + { "ucircumflex", 0x00fb }, + { "Ohungarumlaut", 0x0150 }, + { "Uhungarumlaut", 0x0170 }, + { "Yacute", 0x00dd }, + { "Eth", 0x00d0 }, + { "Dcroat", 0x0110 }, + { "Zacute", 0x0179 }, + { "Uring", 0x016e }, + { "gbreve", 0x011f }, + { "eogonek", 0x0119 }, + { "edotaccent", 0x0117 }, + { "ecaron", 0x011b }, + { "Ugrave", 0x00d9 }, + { "Thorn", 0x00de }, + { "eacute", 0x00e9 }, + { "edieresis", 0x00eb }, + { "dcaron", 0x010f }, + { "ccedilla", 0x00e7 }, + { "ccaron", 0x010d }, + { "cacute", 0x0107 }, + { "aogonek", 0x0105 }, + { "aring", 0x00e5 }, + { "atilde", 0x00e3 }, + { "abreve", 0x0103 }, + { "egrave", 0x00e8 }, + { "agrave", 0x00e0 }, + { "aacute", 0x00e1 }, + { "adieresis", 0x00e4 }, + { "Uogonek", 0x0172 }, + { "ugrave", 0x00f9 }, + { "uacute", 0x00fa }, + { "udieresis", 0x00fc }, + { "tcaron", 0x0165 }, + { "scommaaccent", 0x0219 }, + { "Zcaron", 0x017d }, + { "ecircumflex", 0x00ea }, + { "Ucircumflex", 0x00db }, + { "acircumflex", 0x00e2 }, + { "Zdotaccent", 0x017b }, + { "scaron", 0x0161 }, + { "Amacron", 0x0100 }, + { "sacute", 0x015b }, + { "Tcommaaccent", 0x0162 }, + { "Ydieresis", 0x0178 }, + { "thorn", 0x00fe }, + { "Emacron", 0x0112 }, + { "Ograve", 0x00d2 }, + { "Oacute", 0x00d3 }, + { "Odieresis", 0x00d6 }, + { "Ntilde", 0x00d1 }, + { "Ncaron", 0x0147 }, + { "Nacute", 0x0143 }, + { "Lcaron", 0x013d }, + { "Lacute", 0x0139 }, + { "Idotaccent", 0x0130 }, + { "racute", 0x0155 }, + { "Icircumflex", 0x00ce }, + { "ohungarumlaut", 0x0151 }, + { "otilde", 0x00f5 }, + { "Euro", 0x20ac }, + { "ocircumflex", 0x00f4 }, + { "onesuperior", 0x00b9 }, + { "twosuperior", 0x00b2 }, + { "threesuperior", 0x00b3 }, + { "Igrave", 0x00cc }, + { "Iacute", 0x00cd }, + { "Imacron", 0x012a }, + { "Iogonek", 0x012e }, + { "Idieresis", 0x00cf }, + { "Gbreve", 0x011e }, + { "Umacron", 0x016a }, + { "Kcommaaccent", 0x0136 }, + { "ograve", 0x00f2 }, + { "Scommaaccent", 0x0218 }, + { "Eogonek", 0x0118 }, + { "oacute", 0x00f3 }, + { "Edotaccent", 0x0116 }, + { "iogonek", 0x012f }, + { "gcommaaccent", 0x0123 }, + { "odieresis", 0x00f6 }, + { "ntilde", 0x00f1 }, + { "ncaron", 0x0148 }, + { "Ecaron", 0x011a }, + { "Ecircumflex", 0x00ca }, + { "scedilla", 0x015f }, + { "rcaron", 0x0159 }, + { "Egrave", 0x00c8 }, + { "Eacute", 0x00c9 }, + { "Gcommaaccent", 0x0122 }, + { "Rcommaaccent", 0x0156 }, + { "Edieresis", 0x00cb }, + { "nacute", 0x0144 }, + { "uogonek", 0x0173 }, + { "umacron", 0x016b }, + { "Dcaron", 0x010e }, + { "lcaron", 0x013e }, + { "Ccaron", 0x010c }, + { "Cacute", 0x0106 }, + { "Ccedilla", 0x00c7 }, + { "degree", 0x00b0 }, + { "Aogonek", 0x0104 }, + { "minus", 0x2212 }, + { "multiply", 0x00d7 }, + { "divide", 0x00f7 }, + { "Aring", 0x00c5 }, + { "trademark", 0x2122 }, + { "rcommaaccent", 0x0157 }, + { "lacute", 0x013a }, + { "omacron", 0x014d }, + { "Atilde", 0x00c3 }, + { "icircumflex", 0x00ee }, + { "igrave", 0x00ec }, + { "ncommaaccent", 0x0146 }, + { "lcommaaccent", 0x013c }, + { "plusminus", 0x00b1 }, + { "onehalf", 0x00bd }, + { "onequarter", 0x00bc }, + { "threequarters", 0x00be }, + { "iacute", 0x00ed }, + { "Abreve", 0x0102 }, + { "kcommaaccent", 0x0137 }, + { "Omacron", 0x014c }, + { "imacron", 0x012b }, + { "emacron", 0x0113 }, + { "amacron", 0x0101 }, + { "tcommaaccent", 0x0163 }, + { "ydieresis", 0x00ff }, + { "zdotaccent", 0x017c }, + { "zcaron", 0x017e }, + { "zacute", 0x017a }, + { "yacute", 0x00fd }, + { "uhungarumlaut", 0x0171 }, + { "eth", 0x00f0 }, + { "uring", 0x016f }, + { "Ocircumflex", 0x00d4 }, + { "commaaccent", 0xf6c3 }, + { "copyright", 0x00a9 }, + { "registered", 0x00ae }, + { "Acircumflex", 0x00c2 }, + { "idieresis", 0x00ef }, + { "lozenge", 0x25ca }, + { "Delta", 0x2206 }, + { "notequal", 0x2260 }, + { "radical", 0x221a }, + { "Agrave", 0x00c0 }, + { "Aacute", 0x00c1 }, + { "lessequal", 0x2264 }, + { "greaterequal", 0x2265 }, + { "logicalnot", 0x00ac }, + { "summation", 0x2211 }, + { "partialdiff", 0x2202 }, + { "Ncommaaccent", 0x0145 }, + { "dcroat", 0x0111 }, + { "brokenbar", 0x00a6 }, + { "Lcommaaccent", 0x013b }, + { "Adieresis", 0x00c4 }, + { "mu", 0x00b5 } +}; + +#define NR_GLYPHNAMES (sizeof(x49gp_glyphs) / sizeof(x49gp_glyphs[0])) + +#endif /* !(_X49GP_GLYPHNAME_H) */ diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..ccf9148 --- /dev/null +++ b/include/list.h @@ -0,0 +1,600 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include + +static inline void prefetch(const void *x) {;} + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifdef QEMU_OLD +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against removal of list entry. + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = rcu_dereference(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = rcu_dereference(pos->next)) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = rcu_dereference(n), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = rcu_dereference(list_entry(pos->member.next, \ + typeof(*pos), member))) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next; prefetch((pos)->next), (pos) != (head); \ + (pos) = rcu_dereference((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_for_each_rcu(pos, head) \ + for ((pos) = (head)->first; pos && ({ prefetch((pos)->next); 1; }); \ + (pos) = rcu_dereference((pos)->next)) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_head_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = rcu_dereference(pos->next)) + +#endif /* _LINUX_LIST_H */ diff --git a/include/s3c2410.h b/include/s3c2410.h new file mode 100644 index 0000000..53d1b58 --- /dev/null +++ b/include/s3c2410.h @@ -0,0 +1,348 @@ +/* $Id: s3c2410.h,v 1.18 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_S3C2410_H +#define _X49GP_S3C2410_H 1 + +#include + +typedef struct { + const char *name; + uint32_t reset; + uint32_t *datap; +} s3c2410_offset_t; + +#define S3C2410_OFFSET(module, name, reset, data) \ + [S3C2410_ ## module ## _ ## name >> 2] = { #name, reset, &(data) } + +#define S3C2410_OFFSET_OK(p, offset) \ + ((((offset) >> 2) < (p)->nr_regs) && (p)->regs[(offset) >> 2].name) + +#define S3C2410_OFFSET_ENTRY(p, offset) &((p)->regs[(offset) >> 2]) + + +#define S3C2410_MAP_SIZE 0x00010000 + + +#define S3C2410_SRAM_BASE 0x40000000 +#define S3C2410_SRAM_SIZE 0x00001000 + +#define S3C2410_MEMC_BASE 0x48000000 + +#define S3C2410_MEMC_BWSCON 0x0000 +#define S3C2410_MEMC_BANKCON0 0x0004 +#define S3C2410_MEMC_BANKCON1 0x0008 +#define S3C2410_MEMC_BANKCON2 0x000c +#define S3C2410_MEMC_BANKCON3 0x0010 +#define S3C2410_MEMC_BANKCON4 0x0014 +#define S3C2410_MEMC_BANKCON5 0x0018 +#define S3C2410_MEMC_BANKCON6 0x001c +#define S3C2410_MEMC_BANKCON7 0x0020 +#define S3C2410_MEMC_REFRESH 0x0024 +#define S3C2410_MEMC_BANKSIZE 0x0028 +#define S3C2410_MEMC_MRSRB6 0x002c +#define S3C2410_MEMC_MRSRB7 0x0030 + +#define S3C2410_USBHOST_BASE 0x49000000 + +#define S3C2410_INTC_BASE 0x4a000000 + +#define S3C2410_INTC_SRCPND 0x0000 +#define S3C2410_INTC_INTMOD 0x0004 +#define S3C2410_INTC_INTMSK 0x0008 +#define S3C2410_INTC_PRIORITY 0x000c +#define S3C2410_INTC_INTPND 0x0010 +#define S3C2410_INTC_INTOFFSET 0x0014 +#define S3C2410_INTC_SUBSRCPND 0x0018 +#define S3C2410_INTC_INTSUBMSK 0x001c + +#define S3C2410_POWER_BASE 0x4c000000 + +#define S3C2410_POWER_LOCKTIME 0x0000 +#define S3C2410_POWER_MPLLCON 0x0004 +#define S3C2410_POWER_UPLLCON 0x0008 +#define S3C2410_POWER_CLKCON 0x000c +#define S3C2410_POWER_CLKSLOW 0x0010 +#define S3C2410_POWER_CLKDIVN 0x0014 + +#define S3C2410_LCD_BASE 0x4d000000 + +#define S3C2410_LCD_LCDCON1 0x0000 +#define S3C2410_LCD_LCDCON2 0x0004 +#define S3C2410_LCD_LCDCON3 0x0008 +#define S3C2410_LCD_LCDCON4 0x000c +#define S3C2410_LCD_LCDCON5 0x0010 +#define S3C2410_LCD_LCDSADDR1 0x0014 +#define S3C2410_LCD_LCDSADDR2 0x0018 +#define S3C2410_LCD_LCDSADDR3 0x001c +#define S3C2410_LCD_REDLUT 0x0020 +#define S3C2410_LCD_GREENLUT 0x0024 +#define S3C2410_LCD_BLUELUT 0x0028 +#define S3C2410_LCD_DITHMODE 0x004c +#define S3C2410_LCD_TPAL 0x0050 +#define S3C2410_LCD_LCDINTPND 0x0054 +#define S3C2410_LCD_LCDSRCPND 0x0058 +#define S3C2410_LCD_LCDINTMSK 0x005c +#define S3C2410_LCD_LPCSEL 0x0060 +#define S3C2410_LCD_UNKNOWN_68 0x0068 + +#define S3C2410_LCD_PALETTE_START 0x0400 +#define S3C2410_LCD_PALETTE_SIZE 0x0400 + +#define S3C2410_NAND_BASE 0x4e000000 + +#define S3C2410_NAND_NFCONF 0x0000 +#define S3C2410_NAND_NFCMD 0x0004 +#define S3C2410_NAND_NFADDR 0x0008 +#define S3C2410_NAND_NFDATA 0x000c +#define S3C2410_NAND_NFSTAT 0x0010 +#define S3C2410_NAND_NFECC 0x0014 + +#define S3C2410_UART0_BASE 0x50000000 +#define S3C2410_UART1_BASE 0x50004000 +#define S3C2410_UART2_BASE 0x50008000 + +#define S3C2410_UART0_ULCON 0x0000 +#define S3C2410_UART0_UCON 0x0004 +#define S3C2410_UART0_UFCON 0x0008 +#define S3C2410_UART0_UMCON 0x000c +#define S3C2410_UART0_UTRSTAT 0x0010 +#define S3C2410_UART0_UERSTAT 0x0014 +#define S3C2410_UART0_UFSTAT 0x0018 +#define S3C2410_UART0_UMSTAT 0x001c +#define S3C2410_UART0_UTXH 0x0020 +#define S3C2410_UART0_URXH 0x0024 +#define S3C2410_UART0_UBRDIV 0x0028 + +#define S3C2410_UART1_ULCON 0x0000 +#define S3C2410_UART1_UCON 0x0004 +#define S3C2410_UART1_UFCON 0x0008 +#define S3C2410_UART1_UMCON 0x000c +#define S3C2410_UART1_UTRSTAT 0x0010 +#define S3C2410_UART1_UERSTAT 0x0014 +#define S3C2410_UART1_UFSTAT 0x0018 +#define S3C2410_UART1_UMSTAT 0x001c +#define S3C2410_UART1_UTXH 0x0020 +#define S3C2410_UART1_URXH 0x0024 +#define S3C2410_UART1_UBRDIV 0x0028 + +#define S3C2410_UART2_ULCON 0x0000 +#define S3C2410_UART2_UCON 0x0004 +#define S3C2410_UART2_UFCON 0x0008 +#define S3C2410_UART2_UTRSTAT 0x0010 +#define S3C2410_UART2_UERSTAT 0x0014 +#define S3C2410_UART2_UFSTAT 0x0018 +#define S3C2410_UART2_UTXH 0x0020 +#define S3C2410_UART2_URXH 0x0024 +#define S3C2410_UART2_UBRDIV 0x0028 + +#define S3C2410_TIMER_BASE 0x51000000 + +#define S3C2410_TIMER_TCFG0 0x0000 +#define S3C2410_TIMER_TCFG1 0x0004 +#define S3C2410_TIMER_TCON 0x0008 +#define S3C2410_TIMER_TCNTB0 0x000c +#define S3C2410_TIMER_TCMPB0 0x0010 +#define S3C2410_TIMER_TCNTO0 0x0014 +#define S3C2410_TIMER_TCNTB1 0x0018 +#define S3C2410_TIMER_TCMPB1 0x001c +#define S3C2410_TIMER_TCNTO1 0x0020 +#define S3C2410_TIMER_TCNTB2 0x0024 +#define S3C2410_TIMER_TCMPB2 0x0028 +#define S3C2410_TIMER_TCNTO2 0x002c +#define S3C2410_TIMER_TCNTB3 0x0030 +#define S3C2410_TIMER_TCMPB3 0x0034 +#define S3C2410_TIMER_TCNTO3 0x0038 +#define S3C2410_TIMER_TCNTB4 0x003c +#define S3C2410_TIMER_TCNTO4 0x0040 + +#define S3C2410_USBDEV_BASE 0x52000000 + +#define S3C2410_USBDEV_FUNC_ADDR_REG 0x0140 +#define S3C2410_USBDEV_PWR_REG 0x0144 +#define S3C2410_USBDEV_EP_INT_REG 0x0148 +#define S3C2410_USBDEV_USB_INT_REG 0x0158 +#define S3C2410_USBDEV_EP_INT_EN_REG 0x015c +#define S3C2410_USBDEV_USB_INT_EN_REG 0x016c +#define S3C2410_USBDEV_FRAME_NUM1_REG 0x0170 +#define S3C2410_USBDEV_FRAME_NUM2_REG 0x0174 +#define S3C2410_USBDEV_INDEX_REG 0x0178 +#define S3C2410_USBDEV_EP0_FIFO_REG 0x01C0 +#define S3C2410_USBDEV_EP1_FIFO_REG 0x01C4 +#define S3C2410_USBDEV_EP2_FIFO_REG 0x01C8 +#define S3C2410_USBDEV_EP3_FIFO_REG 0x01CC +#define S3C2410_USBDEV_EP4_FIFO_REG 0x01D0 +#define S3C2410_USBDEV_EP1_DMA_CON 0x0200 +#define S3C2410_USBDEV_EP1_DMA_UNIT 0x0204 +#define S3C2410_USBDEV_EP1_DMA_FIFO 0x0208 +#define S3C2410_USBDEV_EP1_DMA_TTC_L 0x020C +#define S3C2410_USBDEV_EP1_DMA_TTC_M 0x0210 +#define S3C2410_USBDEV_EP1_DMA_TTC_H 0x0214 +#define S3C2410_USBDEV_EP2_DMA_CON 0x0218 +#define S3C2410_USBDEV_EP2_DMA_UNIT 0x021C +#define S3C2410_USBDEV_EP2_DMA_FIFO 0x0220 +#define S3C2410_USBDEV_EP2_DMA_TTC_L 0x0224 +#define S3C2410_USBDEV_EP2_DMA_TTC_M 0x0228 +#define S3C2410_USBDEV_EP2_DMA_TTC_H 0x022C +#define S3C2410_USBDEV_EP3_DMA_CON 0x0240 +#define S3C2410_USBDEV_EP3_DMA_UNIT 0x0244 +#define S3C2410_USBDEV_EP3_DMA_FIFO 0x0248 +#define S3C2410_USBDEV_EP3_DMA_TTC_L 0x024C +#define S3C2410_USBDEV_EP3_DMA_TTC_M 0x0250 +#define S3C2410_USBDEV_EP3_DMA_TTC_H 0x0254 +#define S3C2410_USBDEV_EP4_DMA_CON 0x0258 +#define S3C2410_USBDEV_EP4_DMA_UNIT 0x025C +#define S3C2410_USBDEV_EP4_DMA_FIFO 0x0260 +#define S3C2410_USBDEV_EP4_DMA_TTC_L 0x0264 +#define S3C2410_USBDEV_EP4_DMA_TTC_M 0x0268 +#define S3C2410_USBDEV_EP4_DMA_TTC_H 0x026C +#define S3C2410_USBDEV_MAXP_REG_WRONG 0x0180 +#define S3C2410_USBDEV_IN_CSR1_REG_EP0_CSR 0x0184 +#define S3C2410_USBDEV_IN_CSR2_REG 0x0188 +#define S3C2410_USBDEV_MAXP_REG 0x018c +#define S3C2410_USBDEV_OUT_CSR1_REG 0x0190 +#define S3C2410_USBDEV_OUT_CSR2_REG 0x0194 +#define S3C2410_USBDEV_OUT_FIFO_CNT1_REG 0x0198 +#define S3C2410_USBDEV_OUT_FIFO_CNT2_REG 0x019C + +#define S3C2410_WATCHDOG_BASE 0x53000000 + +#define S3C2410_WATCHDOG_WTCON 0x0000 +#define S3C2410_WATCHDOG_WTDAT 0x0004 +#define S3C2410_WATCHDOG_WTCNT 0x0008 + +#define S3C2410_IO_PORT_BASE 0x56000000 + +#define S3C2410_IO_PORT_GPACON 0x0000 +#define S3C2410_IO_PORT_GPADAT 0x0004 +#define S3C2410_IO_PORT_GPBCON 0x0010 +#define S3C2410_IO_PORT_GPBDAT 0x0014 +#define S3C2410_IO_PORT_GPBUP 0x0018 +#define S3C2410_IO_PORT_GPCCON 0x0020 +#define S3C2410_IO_PORT_GPCDAT 0x0024 +#define S3C2410_IO_PORT_GPCUP 0x0028 +#define S3C2410_IO_PORT_GPDCON 0x0030 +#define S3C2410_IO_PORT_GPDDAT 0x0034 +#define S3C2410_IO_PORT_GPDUP 0x0038 +#define S3C2410_IO_PORT_GPECON 0x0040 +#define S3C2410_IO_PORT_GPEDAT 0x0044 +#define S3C2410_IO_PORT_GPEUP 0x0048 +#define S3C2410_IO_PORT_GPFCON 0x0050 +#define S3C2410_IO_PORT_GPFDAT 0x0054 +#define S3C2410_IO_PORT_GPFUP 0x0058 +#define S3C2410_IO_PORT_GPGCON 0x0060 +#define S3C2410_IO_PORT_GPGDAT 0x0064 +#define S3C2410_IO_PORT_GPGUP 0x0068 +#define S3C2410_IO_PORT_GPHCON 0x0070 +#define S3C2410_IO_PORT_GPHDAT 0x0074 +#define S3C2410_IO_PORT_GPHUP 0x0078 +#define S3C2410_IO_PORT_MISCCR 0x0080 +#define S3C2410_IO_PORT_DCLKCON 0x0084 +#define S3C2410_IO_PORT_EXTINT0 0x0088 +#define S3C2410_IO_PORT_EXTINT1 0x008c +#define S3C2410_IO_PORT_EXTINT2 0x0090 +#define S3C2410_IO_PORT_EINTFLT0 0x0094 +#define S3C2410_IO_PORT_EINTFLT1 0x0098 +#define S3C2410_IO_PORT_EINTFLT2 0x009c +#define S3C2410_IO_PORT_EINTFLT3 0x00a0 +#define S3C2410_IO_PORT_EINTMASK 0x00a4 +#define S3C2410_IO_PORT_EINTPEND 0x00a8 +#define S3C2410_IO_PORT_GSTATUS0 0x00ac +#define S3C2410_IO_PORT_GSTATUS1 0x00b0 +#define S3C2410_IO_PORT_GSTATUS2 0x00b4 +#define S3C2410_IO_PORT_GSTATUS3 0x00b8 +#define S3C2410_IO_PORT_GSTATUS4 0x00bc + +#define S3C2410_RTC_BASE 0x57000000 + +#define S3C2410_RTC_RTCCON 0x0040 +#define S3C2410_RTC_TICNT 0x0044 +#define S3C2410_RTC_RTCALM 0x0050 +#define S3C2410_RTC_ALMSEC 0x0054 +#define S3C2410_RTC_ALMMIN 0x0058 +#define S3C2410_RTC_ALMHOUR 0x005c +#define S3C2410_RTC_ALMDATE 0x0060 +#define S3C2410_RTC_ALMMON 0x0064 +#define S3C2410_RTC_ALMYEAR 0x0068 +#define S3C2410_RTC_RTCRST 0x006c +#define S3C2410_RTC_BCDSEC 0x0070 +#define S3C2410_RTC_BCDMIN 0x0074 +#define S3C2410_RTC_BCDHOUR 0x0078 +#define S3C2410_RTC_BCDDATE 0x007c +#define S3C2410_RTC_BCDDAY 0x0080 +#define S3C2410_RTC_BCDMON 0x0084 +#define S3C2410_RTC_BCDYEAR 0x0088 + +#define S3C2410_ADC_BASE 0x58000000 + +#define S3C2410_ADC_ADCCON 0x0000 +#define S3C2410_ADC_ADCTSC 0x0004 +#define S3C2410_ADC_ADCDLY 0x0008 +#define S3C2410_ADC_ADCDAT0 0x000c +#define S3C2410_ADC_ADCDAT1 0x0010 + +#define S3C2410_SPI_BASE 0x59000000 + +#define S3C2410_SPI_SPICON0 0x0000 +#define S3C2410_SPI_SPISTA0 0x0004 +#define S3C2410_SPI_SPPIN0 0x0008 +#define S3C2410_SPI_SPPRE0 0x000c +#define S3C2410_SPI_SPTDAT0 0x0010 +#define S3C2410_SPI_SPRDAT0 0x0014 +#define S3C2410_SPI_SPICON1 0x0020 +#define S3C2410_SPI_SPISTA1 0x0024 +#define S3C2410_SPI_SPPIN1 0x0028 +#define S3C2410_SPI_SPPRE1 0x002c +#define S3C2410_SPI_SPTDAT1 0x0030 +#define S3C2410_SPI_SPRDAT1 0x0034 + +#define S3C2410_SDI_BASE 0x5a000000 + +#define S3C2410_SDI_SDICON 0x0000 +#define S3C2410_SDI_SDIPRE 0x0004 +#define S3C2410_SDI_SDICARG 0x0008 +#define S3C2410_SDI_SDICCON 0x000c +#define S3C2410_SDI_SDICSTA 0x0010 +#define S3C2410_SDI_SDIRSP0 0x0014 +#define S3C2410_SDI_SDIRSP1 0x0018 +#define S3C2410_SDI_SDIRSP2 0x001c +#define S3C2410_SDI_SDIRSP3 0x0020 +#define S3C2410_SDI_SDIDTIMER 0x0024 +#define S3C2410_SDI_SDIBSIZE 0x0028 +#define S3C2410_SDI_SDIDCON 0x002c +#define S3C2410_SDI_SDIDCNT 0x0030 +#define S3C2410_SDI_SDIDSTA 0x0034 +#define S3C2410_SDI_SDIFSTA 0x0038 +#define S3C2410_SDI_SDIDAT 0x003c +#define S3C2410_SDI_SDIIMSK 0x0040 + + +extern int x49gp_s3c2410_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_arm_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_mmu_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_sram_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_memc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_intc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_power_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_lcd_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_nand_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_uart_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_timer_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_usbdev_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_watchdog_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_io_port_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_rtc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_adc_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_spi_init(x49gp_t *x49gp); +extern int x49gp_s3c2410_sdi_init(x49gp_t *x49gp); + +extern void s3c2410_io_port_g_set_bit(x49gp_t *x49gp, int n, uint32_t set); +extern void s3c2410_io_port_f_set_bit(x49gp_t *x49gp, int n, uint32_t set); + +extern void x49gp_schedule_lcd_update(x49gp_t *x49gp); +extern void x49gp_lcd_update(x49gp_t *x49gp); + +extern unsigned long s3c2410_timer_next_interrupt(x49gp_t *x49gp); +extern unsigned long s3c2410_watchdog_next_interrupt(x49gp_t *x49gp); + +#endif /* !(_X49GP_S3C2410_H) */ diff --git a/include/s3c2410_intc.h b/include/s3c2410_intc.h new file mode 100644 index 0000000..b3c5ffd --- /dev/null +++ b/include/s3c2410_intc.h @@ -0,0 +1,72 @@ +/* $Id: s3c2410_intc.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_S3C2410_INTC_H +#define _X49GP_S3C2410_INTC_H 1 + +#define INT_ADC 31 +#define INT_RTC 30 +#define INT_SPI1 29 +#define INT_UART0 28 +#define INT_IIC 27 +#define INT_USBH 26 +#define INT_USBD 25 +#define INT_UART1 23 +#define INT_SPI0 22 +#define INT_SDI 21 +#define INT_DMA3 20 +#define INT_DMA2 19 +#define INT_DMA1 18 +#define INT_DMA0 17 +#define INT_LCD 16 +#define INT_UART2 15 +#define INT_TIMER4 14 +#define INT_TIMER3 13 +#define INT_TIMER2 12 +#define INT_TIMER1 11 +#define INT_TIMER0 10 +#define INT_WDT 9 +#define INT_TICK 8 +#define nBATT_FLT 7 +#define EINT8_23 5 +#define EINT4_7 4 +#define EINT3 3 +#define EINT2 2 +#define EINT1 1 +#define EINT0 0 + +#define SUB_INT_ADC 10 +#define SUB_INT_TC 9 +#define SUB_INT_ERR2 8 +#define SUB_INT_TXD2 7 +#define SUB_INT_RXD2 6 +#define SUB_INT_ERR1 5 +#define SUB_INT_TXD1 4 +#define SUB_INT_RXD1 3 +#define SUB_INT_ERR0 2 +#define SUB_INT_TXD0 1 +#define SUB_INT_RXD0 0 + +#define ARB0_MODE (1 << 0) +#define ARB1_MODE (1 << 1) +#define ARB2_MODE (1 << 2) +#define ARB3_MODE (1 << 3) +#define ARB4_MODE (1 << 4) +#define ARB5_MODE (1 << 5) +#define ARB6_MODE (1 << 6) +#define ARB0_SEL_SHIFT 7 +#define ARB1_SEL_SHIFT 9 +#define ARB2_SEL_SHIFT 11 +#define ARB3_SEL_SHIFT 13 +#define ARB4_SEL_SHIFT 15 +#define ARB5_SEL_SHIFT 17 +#define ARB6_SEL_SHIFT 19 +#define ARBx_SEL_MASK 3 + +void s3c2410_intc_sub_assert(x49gp_t *x49gp, int sub_irq, int level); +void s3c2410_intc_sub_deassert(x49gp_t *x49gp, int sub_irq); + +void s3c2410_intc_assert(x49gp_t *x49gp, int irq, int level); +void s3c2410_intc_deassert(x49gp_t *x49gp, int irq); + +#endif /* !(_X49GP_S3C2410_INTC_H) */ diff --git a/include/s3c2410_mmu.h b/include/s3c2410_mmu.h new file mode 100644 index 0000000..561e2da --- /dev/null +++ b/include/s3c2410_mmu.h @@ -0,0 +1,37 @@ +/* $Id: s3c2410_mmu.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_MMU_H +#define _S3C2410_MMU_H 1 + +#define S3C2410_MMU_TLB_SIZE 64 +#define S3C2410_MMU_TLB_MASK (S3C2410_MMU_TLB_SIZE - 1) + +typedef struct { + uint32_t mva; + uint32_t mask; + uint32_t pa; + uint32_t dac; + int valid; +} TLB_entry_t; + +typedef struct { + int victim; + int base; + int index0; + int index1; + unsigned long hit0; + unsigned long hit1; + unsigned long search; + unsigned long nsearch; + unsigned long walk; + TLB_entry_t data[S3C2410_MMU_TLB_SIZE]; +} TLB_t; + +typedef struct { + uint32_t MMUReg[16]; + TLB_t iTLB; + TLB_t dTLB; +} s3c2410_mmu_t; + +#endif /* !(_S3C2410_MMU_H) */ diff --git a/include/s3c2410_power.h b/include/s3c2410_power.h new file mode 100644 index 0000000..88c3a57 --- /dev/null +++ b/include/s3c2410_power.h @@ -0,0 +1,28 @@ +/* $Id: s3c2410_power.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_POWER_H +#define _S3C2410_POWER_H 1 + +#define CLKCON_SPI 0x00040000 +#define CLKCON_IIS 0x00020000 +#define CLKCON_IIC 0x00010000 +#define CLKCON_ADC 0x00008000 +#define CLKCON_RTC 0x00004000 +#define CLKCON_GPIO 0x00002000 +#define CLKCON_UART2 0x00001000 +#define CLKCON_UART1 0x00000800 +#define CLKCON_UART0 0x00000400 +#define CLKCON_SDI 0x00000200 +#define CLKCON_TIMER 0x00000100 +#define CLKCON_USBD 0x00000080 +#define CLKCON_USBH 0x00000040 +#define CLKCON_LCD 0x00000020 +#define CLKCON_NAND 0x00000010 +#define CLKCON_POWER_OFF 0x00000008 +#define CLKCON_IDLE 0x00000004 +#define CLKCON_SM_BIT 0x00000001 + +extern int s3c2410_idle; + +#endif /* !(_S3C2410_POWER_H) */ diff --git a/include/s3c2410_timer.h b/include/s3c2410_timer.h new file mode 100644 index 0000000..5fcfe25 --- /dev/null +++ b/include/s3c2410_timer.h @@ -0,0 +1,48 @@ +/* $Id: s3c2410_timer.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _S3C2410_TIMER_H +#define _S3C2410_TIMER_H 1 + +#include + +#define TCFG0_DEAD_SHIFT 16 +#define TCFG0_DEAD_MASK 0xff +#define TCFG0_PRE1_SHIFT 8 +#define TCFG0_PRE0_SHIFT 0 +#define TCFG0_PREx_MASK 0xff + +#define TCFG1_DMA_SHIFT 20 +#define TCFG1_DMA_MASK 0x0f +#define TCFG1_MUX4_SHIFT 16 +#define TCFG1_MUX3_SHIFT 12 +#define TCFG1_MUX2_SHIFT 8 +#define TCFG1_MUX1_SHIFT 4 +#define TCFG1_MUX0_SHIFT 0 +#define TCFG1_MUXx_MASK 0x0f + +#define TCON_TIMER4_RELOAD 0x00400000 +#define TCON_TIMER4_UPDATE 0x00200000 +#define TCON_TIMER4_START 0x00100000 +#define TCON_TIMER3_RELOAD 0x00080000 +#define TCON_TIMER3_INVERT 0x00040000 +#define TCON_TIMER3_UPDATE 0x00020000 +#define TCON_TIMER3_START 0x00010000 +#define TCON_TIMER2_RELOAD 0x00008000 +#define TCON_TIMER2_INVERT 0x00004000 +#define TCON_TIMER2_UPDATE 0x00002000 +#define TCON_TIMER2_START 0x00001000 +#define TCON_TIMER1_RELOAD 0x00000800 +#define TCON_TIMER1_INVERT 0x00000400 +#define TCON_TIMER1_UPDATE 0x00000200 +#define TCON_TIMER1_START 0x00000100 +#define TCON_TIMER0_DEADZONE 0x00000010 +#define TCON_TIMER0_RELOAD 0x00000008 +#define TCON_TIMER0_INVERT 0x00000004 +#define TCON_TIMER0_UPDATE 0x00000002 +#define TCON_TIMER0_START 0x00000001 + +void s3c2410_run_timers(x49gp_t *x49gp); +clock_t s3c2410_next_timer(x49gp_t *x49gp); + +#endif /* !(_S3C2410_TIMER_H) */ diff --git a/include/saturn.h b/include/saturn.h new file mode 100644 index 0000000..b1102ff --- /dev/null +++ b/include/saturn.h @@ -0,0 +1,43 @@ +/* $Id: saturn.h,v 1.1 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef SATURN_H +#define SATURN_H 1 + +#define NB_RSTK 8 + +typedef uint64_t saturn_reg_t; + +typedef struct { + uint32_t read_map[256 + 1]; + uint32_t write_map[256 + 1]; + uint8_t top_map[256 + 1 + 3]; + saturn_reg_t A; + saturn_reg_t B; + saturn_reg_t C; + saturn_reg_t D; + saturn_reg_t R0; + saturn_reg_t R1; + saturn_reg_t R2; + saturn_reg_t R3; + saturn_reg_t R4; + uint32_t D0; + uint32_t D1; + uint32_t P, P4, P4_32; + uint32_t ST; + uint32_t HST; + uint32_t carry; + int dec; + uint32_t RSTK[NB_RSTK]; + uint32_t RSTK_i; + uint32_t REG_FIELD[32]; + uint32_t FIELD_START[32]; + uint32_t FIELD_LENGTH[32]; +} saturn_cpu_t; + +#define SAT_RPLTOP 0x8076b +#define SAT_RSKTOP 0x806f3 /* RETTOP */ +#define SAT_DSKTOP 0x806f8 +#define SAT_EDITLINE 0x806fd + +#endif /* !(SATURN_H) */ diff --git a/include/symbol.h b/include/symbol.h new file mode 100644 index 0000000..53174f6 --- /dev/null +++ b/include/symbol.h @@ -0,0 +1,68 @@ +/* $Id: symbol.h,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_SYMBOL_H +#define _X49GP_SYMBOL_H 1 + +#include + +typedef struct { + const cairo_path_data_t *data; + int num_data; +} symbol_path_t; + +typedef struct { + double x_advance; + double y_advance; + double llx; + double lly; + double urx; + double ury; + double prescale; + double postscale; + const symbol_path_t *path; +} x49gp_symbol_t; + +#define SYMBOL_MOVE_TO(x, y) \ + { header: { CAIRO_PATH_MOVE_TO, 2 } }, \ + { point: { x, y } } + +#define SYMBOL_LINE_TO(x, y) \ + { header: { CAIRO_PATH_LINE_TO, 2 } }, \ + { point: { x, y } } + +#define SYMBOL_CURVE_TO(x1, y1, x2, y2, x3, y3) \ + { header: { CAIRO_PATH_CURVE_TO, 4 } }, \ + { point: { x1, y1 } }, \ + { point: { x2, y2 } }, \ + { point: { x3, y3 } } + +#define SYMBOL_CLOSE_PATH() \ + { header: { CAIRO_PATH_CLOSE_PATH, 1 } } + +#define SYMBOL(name, x_advance, y_advance, llx, lly, urx, ury) \ +static const symbol_path_t symbol_##name##_path = \ +{ \ + symbol_##name##_path_data, \ + sizeof(symbol_##name##_path_data) / sizeof(cairo_path_data_t) \ +}; \ + \ +static const x49gp_symbol_t symbol_##name = \ +{ \ + x_advance, y_advance, llx, lly, urx, ury, 1.0, 1.0, \ + &symbol_##name##_path \ +} + +#define CONTROL(name, x_advance, y_advance, prescale, postscale) \ +static const x49gp_symbol_t symbol_##name = \ +{ \ + x_advance, y_advance, 0.0, 0.0, 0.0, 0.0, \ + prescale, postscale, NULL \ +} + +int symbol_lookup_glyph_by_name(const char *name, int namelen, gunichar *); + +const x49gp_symbol_t *symbol_get_by_name(const char *name); +const x49gp_symbol_t *symbol_get_by_glyph(gunichar glyph); + +#endif /* !(_X49GP_SYMBOL_H) */ diff --git a/include/x49gp.h b/include/x49gp.h new file mode 100644 index 0000000..6739281 --- /dev/null +++ b/include/x49gp.h @@ -0,0 +1,144 @@ +/* $Id: x49gp.h,v 1.15 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_H +#define _X49GP_H + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +/* LD TEMPO HACK */ +#ifndef QEMU_OLD +extern uint8_t *phys_ram_base; +extern int phys_ram_size; +#endif + +typedef enum { + X49GP_ARM_RUN = 0, + X49GP_ARM_SLEEP, + X49GP_ARM_OFF +} x49gp_arm_idle_t; + +typedef enum { + X49GP_RESET_POWER_ON = 0, + X49GP_RESET_POWER_OFF, + X49GP_RESET_WATCHDOG +} x49gp_reset_t; + +struct __x49gp_module_s__; +typedef struct __x49gp_module_s__ x49gp_module_t; + +struct __x49gp_module_s__ { + const char *name; + + int (*init) (x49gp_module_t *); + int (*exit) (x49gp_module_t *); + + int (*reset) (x49gp_module_t *, x49gp_reset_t); + + int (*load) (x49gp_module_t *, GKeyFile *); + int (*save) (x49gp_module_t *, GKeyFile *); + + void *user_data; + + x49gp_t *x49gp; + struct list_head list; +}; + + +struct __x49gp_s__ { + CPUARMState *env; + + struct list_head modules; + + void *s3c2410_lcd; + void *s3c2410_timer; + void *s3c2410_watchdog; + void *s3c2410_intc; + void *s3c2410_io_port; + + void *timer; + uint8_t *sram; + + uint32_t MCLK; + uint32_t UCLK; + + uint32_t FCLK; + uint32_t HCLK; + uint32_t PCLK; + int PCLK_ratio; + + clock_t clk_tck; + unsigned long emulator_fclk; + + unsigned char keybycol[8]; + unsigned char keybyrow[8]; + + x49gp_timer_t *gtk_timer; + x49gp_timer_t *lcd_timer; + + x49gp_arm_idle_t arm_idle; + int arm_exit; + + x49gp_ui_t *ui; + + GKeyFile *config; + const char *progname; +}; + +extern void x49gp_set_idle(x49gp_t *, x49gp_arm_idle_t idle); + +extern int x49gp_module_init(x49gp_t *x49gp, const char *name, + int (*init)(x49gp_module_t *), + int (*exit)(x49gp_module_t *), + int (*reset)(x49gp_module_t *, x49gp_reset_t), + int (*load)(x49gp_module_t *, GKeyFile *), + int (*save)(x49gp_module_t *, GKeyFile *), + void *user_data, x49gp_module_t **module); + +extern int x49gp_module_register(x49gp_module_t *module); +extern int x49gp_module_unregister(x49gp_module_t *module); + +extern char *x49gp_module_get_filename(x49gp_module_t *module, GKeyFile *, + const char *key); +extern int x49gp_module_get_int(x49gp_module_t *module, GKeyFile *, + const char *, int, int *); +extern int x49gp_module_set_int(x49gp_module_t *module, GKeyFile *, + const char *, int); +extern int x49gp_module_get_uint(x49gp_module_t *module, GKeyFile *, + const char *, + unsigned int, unsigned int *); +extern int x49gp_module_set_uint(x49gp_module_t *module, GKeyFile *, + const char *, unsigned int); +extern int x49gp_module_get_u32(x49gp_module_t *module, GKeyFile *, + const char *, uint32_t, uint32_t *); +extern int x49gp_module_set_u32(x49gp_module_t *module, GKeyFile *, + const char *, uint32_t); +extern int x49gp_module_get_u64(x49gp_module_t *module, GKeyFile *, + const char *, uint64_t, uint64_t *); +extern int x49gp_module_set_u64(x49gp_module_t *module, GKeyFile *, + const char *, uint64_t); +extern int x49gp_module_get_string(x49gp_module_t *module, GKeyFile *, + const char *, char *, char **); + +extern int x49gp_modules_init(x49gp_t *); +extern int x49gp_modules_exit(x49gp_t *); +extern int x49gp_modules_reset(x49gp_t *, x49gp_reset_t); +extern int x49gp_modules_load(x49gp_t *, const char *); +extern int x49gp_modules_save(x49gp_t *, const char *); + +extern int x49gp_flash_init(x49gp_t *); +extern int x49gp_sram_init(x49gp_t *); + +#endif /* !(_X49GP_H) */ diff --git a/include/x49gp_timer.h b/include/x49gp_timer.h new file mode 100644 index 0000000..e5acdcb --- /dev/null +++ b/include/x49gp_timer.h @@ -0,0 +1,32 @@ +/* $Id: x49gp_timer.h,v 1.3 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_TIMER_H +#define _X49GP_TIMER_H 1 + +#include +#include + +#define X49GP_TIMER_VIRTUAL 0 +#define X49GP_TIMER_REALTIME 1 + +int64_t x49gp_get_clock(void); + +typedef void (*x49gp_timer_cb_t) (void *); +typedef struct x49gp_timer_s x49gp_timer_t; + +x49gp_timer_t *x49gp_new_timer(long type, x49gp_timer_cb_t, void *user_data); +void x49gp_free_timer(x49gp_timer_t *); + +void x49gp_mod_timer(x49gp_timer_t *, int64_t expires); +void x49gp_del_timer(x49gp_timer_t *); +int x49gp_timer_pending(x49gp_timer_t *); +int64_t x49gp_timer_expires(x49gp_timer_t *); + +#define X49GP_GTK_REFRESH_INTERVAL 30000LL +#define X49GP_LCD_REFRESH_INTERVAL 50000LL + +int x49gp_main_loop(x49gp_t *); +int x49gp_timer_init(x49gp_t *); + +#endif /* !(_X49GP_TIMER_H) */ diff --git a/include/x49gp_types.h b/include/x49gp_types.h new file mode 100644 index 0000000..f6b52d7 --- /dev/null +++ b/include/x49gp_types.h @@ -0,0 +1,23 @@ +/* $Id: x49gp_types.h,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_TYPES_H +#define _X49GP_TYPES_H 1 + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +struct __x49gp_s__; +typedef struct __x49gp_s__ x49gp_t; + +struct __x49gp_ui_s__; +typedef struct __x49gp_ui_s__ x49gp_ui_t; + +#endif /* !(_X49GP_TYPES_H) */ diff --git a/include/x49gp_ui.h b/include/x49gp_ui.h new file mode 100644 index 0000000..e019b78 --- /dev/null +++ b/include/x49gp_ui.h @@ -0,0 +1,125 @@ +/* $Id: x49gp_ui.h,v 1.14 2008/12/11 12:18:17 ecd Exp $ + */ + +#ifndef _X49GP_UI_H +#define _X49GP_UI_H 1 + +#include + +typedef enum { + UI_COLOR_BLACK = 0, + UI_COLOR_WHITE, + UI_COLOR_YELLOW, + UI_COLOR_RED, + UI_COLOR_GREEN, + UI_COLOR_SILVER, + UI_COLOR_ORANGE, + UI_COLOR_BLUE, + UI_COLOR_MAX +} x49gp_ui_color_t; + +typedef enum { + UI_SHAPE_BUTTON_TINY = 0, + UI_SHAPE_BUTTON_SMALL, + UI_SHAPE_BUTTON_NORMAL, + UI_SHAPE_BUTTON_LARGE, + UI_SHAPE_BUTTON_ROUND, + UI_SHAPE_MAX +} x49gp_ui_shape_t; + +typedef enum { + UI_LAYOUT_LEFT = 0, + UI_LAYOUT_LEFT_NO_SPACE, + UI_LAYOUT_BELOW, + UI_LAYOUT_MAX +} x49gp_ui_layout_t; + +typedef enum { + UI_CALCULATOR_HP49GP = 0, + UI_CALCULATOR_HP50G +} x49gp_ui_calculator_t; + + +typedef struct { + const char *label; + const char *letter; + const char *left; + const char *right; + const char *below; + x49gp_ui_color_t color; + double font_size; + cairo_font_weight_t font_weight; + x49gp_ui_shape_t shape; + double letter_size; + x49gp_ui_layout_t layout; + int x; + int y; + int width; + int height; + int column; + int row; + unsigned char columnbit; + unsigned char rowbit; + int eint; +} x49gp_ui_key_t; + +typedef struct { + x49gp_t *x49gp; + const x49gp_ui_key_t *key; + GtkWidget *button; + GtkWidget *label; + GtkWidget *box; + GdkPixmap *pixmap; + gboolean down; + gboolean hold; +} x49gp_ui_button_t; + +struct __x49gp_ui_s__ { + GtkWidget *window; + GtkWidget *fixed; + + GdkPixbuf *bg_pixbuf; + GdkPixmap *bg_pixmap; + GtkWidget *background; + + GdkColor colors[UI_COLOR_MAX]; + GdkBitmap *shapes[UI_SHAPE_MAX]; + + x49gp_ui_calculator_t calculator; + + x49gp_ui_button_t *buttons; + unsigned int nr_buttons; + + GtkWidget *lcd_canvas; + GdkPixmap *lcd_pixmap; + + GdkGC *ann_left_gc; + GdkGC *ann_right_gc; + GdkGC *ann_alpha_gc; + GdkGC *ann_battery_gc; + GdkGC *ann_busy_gc; + GdkGC *ann_io_gc; + + GdkBitmap *ann_left; + GdkBitmap *ann_right; + GdkBitmap *ann_alpha; + GdkBitmap *ann_battery; + GdkBitmap *ann_busy; + GdkBitmap *ann_io; + + gint width; + gint height; + + gint kb_x_offset; + gint kb_y_offset; + + gint lcd_x_offset; + gint lcd_y_offset; + gint lcd_width; + gint lcd_height; + gint lcd_top_margin; +}; + +int x49gp_ui_init(x49gp_t *x49gp); + +#endif /* !(_X49GP_UI_H) */ diff --git a/le32hex2bin.c b/le32hex2bin.c new file mode 100644 index 0000000..2739c60 --- /dev/null +++ b/le32hex2bin.c @@ -0,0 +1,117 @@ +/* $Id: le32hex2bin.c,v 1.3 2008/12/11 12:18:17 ecd Exp $ + * + * $Log: le32hex2bin.c,v $ + * Revision 1.3 2008/12/11 12:18:17 ecd + * major rework to qemu + * + * Revision 1.1 2006-08-20 17:26:07 ecd + * Modularize most stuff, IO_PORT, INTC, ARM, and MMU still missing. + * + * Revision 1.1 2002/06/19 08:19:39 ecd + * Add Lattice/Xilinx tools + * + * Revision 1.1 2002/01/04 10:46:48 ecd + * initial import + * + * Revision 1.1 1999/12/09 10:53:33 ecd + * add Xilinx conversion tool + * + */ + +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + unsigned char *input, *p; + unsigned char *memory = NULL; + size_t size; + int in, out; + int i; + + if (argc < 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + + if (!strcmp(argv[1], "-")) + in = 0; + else { + in = open(argv[1], O_RDONLY); + if (in < 0) { + perror(argv[1]); + exit(1); + } + } + + if (!strcmp(argv[2], "-")) + out = 1; + else { + out = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (out < 0) { + perror(argv[2]); + exit(1); + } + } + + size = lseek(in, 0, SEEK_END); + lseek(in, 0, SEEK_SET); + + input = (unsigned char *)malloc(size); + if (!input) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(1); + } + + if (read(in, input, size) != size) { + perror("read"); + exit(1); + } + + close(in); + + memory = malloc(size >> 1); + if (!memory) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(1); + } + + p = input; + for (i = 0; i < (size >> 1); i++) { + if ('0' <= *p && *p <= '9') + memory[(i & ~3) + 3 - (i & 3)] = (*p - '0') << 0; + else if ('a' <= *p && *p <= 'f') + memory[(i & ~3) + 3 - (i & 3)] = (*p - 'a' + 10) << 0; + else if ('A' <= *p && *p <= 'F') + memory[(i & ~3) + 3 - (i & 3)] = (*p - 'A' + 10) << 0; + else { + fprintf(stderr, "%s: parse error at byte %d\n", + argv[0], i); + exit(1); + } + p++; + if ('0' <= *p && *p <= '9') + memory[(i & ~3) + 3 - (i & 3)] |= (*p - '0') << 4; + else if ('a' <= *p && *p <= 'f') + memory[(i & ~3) + 3 - (i & 3)] |= (*p - 'a' + 10) << 4; + else if ('A' <= *p && *p <= 'F') + memory[(i & ~3) + 3 - (i & 3)] |= (*p - 'A' + 10) << 4; + else { + fprintf(stderr, "%s: parse error at byte %d\n", + argv[0], i); + exit(1); + } + p++; + } + + write(out, memory, size >> 1); + close(out); + + return 0; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..2ea6338 --- /dev/null +++ b/main.c @@ -0,0 +1,435 @@ +/* $Id: main.c,v 1.30 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gdbstub.h" + +static x49gp_t *x49gp; + +#ifdef QEMU_OLD // LD TEMPO HACK +extern +#endif +CPUState *__GLOBAL_env; + +int semihosting_enabled = 1; + +/* LD TEMPO HACK */ +#ifndef QEMU_OLD +uint8_t *phys_ram_base; +int phys_ram_size; +ram_addr_t ram_size = 0x80000; // LD ??? + +/* vl.c */ +int singlestep; + +void *qemu_memalign(size_t alignment, size_t size) +{ +#if defined(__APPLE__) || defined(_POSIX_C_SOURCE) && !defined(__sun__) + int ret; + void *ptr; + ret = posix_memalign(&ptr, alignment, size); + if (ret != 0) + abort(); + return ptr; +#elif defined(CONFIG_BSD) + return oom_check(valloc(size)); +#else + return oom_check(memalign(alignment, size)); +#endif +} + + +void qemu_init_vcpu(void *_env) +{ + CPUState *env = _env; + + env->nr_cores = 1; + env->nr_threads = 1; +} + +int qemu_cpu_self(void *env) +{ + return 1; +} + +void qemu_cpu_kick(void *env) +{ +} + +void armv7m_nvic_set_pending(void *opaque, int irq) +{ + abort(); +} +int armv7m_nvic_acknowledge_irq(void *opaque) +{ + abort(); +} +void armv7m_nvic_complete_irq(void *opaque, int irq) +{ + abort(); +} + +void gdb_register_coprocessor(CPUState * env, + void * get_reg, void * set_reg, + int num_regs, const char *xml, int g_pos) +{ + fprintf(stderr, "TODO: %s\n", __FUNCTION__); +} + +#endif /* !QEMU_OLD */ + +void * +qemu_malloc(size_t size) +{ + return malloc(size); +} + +void * +qemu_mallocz(size_t size) +{ + void *ptr; + + ptr = qemu_malloc(size); + if (NULL == ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + +void +qemu_free(void *ptr) +{ + free(ptr); +} + +void * +qemu_vmalloc(size_t size) +{ +#if defined(__linux__) + void *mem; + if (0 == posix_memalign(&mem, sysconf(_SC_PAGE_SIZE), size)) + return mem; + return NULL; +#else + return valloc(size); +#endif +} + +#ifdef QEMU_OLD +int +term_vprintf(const char *fmt, va_list ap) +{ + return vprintf(fmt, ap); +} + +int +term_printf(const char *fmt, ...) +{ + va_list ap; + int n; + + va_start(ap, fmt); + n = vprintf(fmt, ap); + va_end(ap); + + return n; +} +#endif + +#define SWI_Breakpoint 0x180000 + +#ifdef QEMU_OLD +int +do_arm_semihosting(CPUState *env, uint32_t number) +#else +uint32_t +do_arm_semihosting(CPUState *env) +#endif +{ +#ifndef QEMU_OLD + uint32_t number; + if (env->thumb) { + number = lduw_code(env->regs[15] - 2) & 0xff; + } else { + number = ldl_code(env->regs[15] - 4) & 0xffffff; + } +#endif + switch (number) { + case SWI_Breakpoint: + break; + + case 0: +#ifdef DEBUG_X49GP_SYSCALL + printf("%s: SWI LR %08x: syscall %u: args %08x %08x %08x %08x %08x %08x %08x\n", + __FUNCTION__, env->regs[14], env->regs[0], + env->regs[1], env->regs[2], env->regs[3], + env->regs[4], env->regs[5], env->regs[6], + env->regs[7]); +#endif + +#if 1 + switch (env->regs[0]) { + case 305: /* Beep */ + printf("%s: BEEP: frequency %u, time %u, override %u\n", + __FUNCTION__, env->regs[1], env->regs[2], env->regs[3]); + + gdk_beep(); + env->regs[0] = 0; + return 1; + + case 28: /* CheckBeepEnd */ + env->regs[0] = 0; + return 1; + + case 29: /* StopBeep */ + env->regs[0] = 0; + return 1; + + default: + break; + } +#endif + break; + + default: + break; + } + + return 0; +} + +void +x49gp_set_idle(x49gp_t *x49gp, x49gp_arm_idle_t idle) +{ +#ifdef DEBUG_X49GP_ARM_IDLE + if (idle != x49gp->arm_idle) { + printf("%s: arm_idle %u, idle %u\n", __FUNCTION__, x49gp->arm_idle, idle); + } +#endif + + x49gp->arm_idle = idle; + + if (x49gp->arm_idle == X49GP_ARM_RUN) { + x49gp->env->halted = 0; + } else { + x49gp->env->halted = 1; +#ifdef QEMU_OLD + cpu_interrupt(x49gp->env, CPU_INTERRUPT_EXIT); +#else + cpu_exit(x49gp->env); +#endif + } +} + +static void +arm_sighnd(int sig) +{ + switch (sig) { + case SIGUSR1: +// stop_simulator = 1; +// x49gp->arm->CallDebug ^= 1; + break; + default: + fprintf(stderr, "%s: sig %u\n", __FUNCTION__, sig); + break; + } +} + +void +x49gp_gtk_timer(void *data) +{ + while (gtk_events_pending()) { +// printf("%s: gtk_main_iteration_do()\n", __FUNCTION__); + gtk_main_iteration_do(FALSE); + } + + x49gp_mod_timer(x49gp->gtk_timer, + x49gp_get_clock() + X49GP_GTK_REFRESH_INTERVAL); +} + +void +x49gp_lcd_timer(void *data) +{ + x49gp_t *x49gp = data; + int64_t now, expires; + +// printf("%s: lcd_update\n", __FUNCTION__); + x49gp_lcd_update(x49gp); + gdk_flush(); + + now = x49gp_get_clock(); + expires = now + X49GP_LCD_REFRESH_INTERVAL; + +// printf("%s: now: %lld, next update: %lld\n", __FUNCTION__, now, expires); + x49gp_mod_timer(x49gp->lcd_timer, expires); +} + +static void +usage(const char *progname) +{ + fprintf(stderr, "usage: %s \n", + progname); + exit(1); +} + +void +ui_sighnd(int sig) +{ + switch (sig) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + x49gp->arm_exit = 1; +#ifdef QEMU_OLD + cpu_interrupt(x49gp->env, CPU_INTERRUPT_EXIT); +#else + cpu_exit(x49gp->env); +#endif + break; + } +} + +int +main(int argc, char **argv) +{ + char *progname; + int error; + + + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + + + gtk_init(&argc, &argv); + + + if (argc < 2) + usage(progname); + + x49gp = malloc(sizeof(x49gp_t)); + if (NULL == x49gp) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + progname, __FUNCTION__, __LINE__); + exit(1); + } + memset(x49gp, 0, sizeof(x49gp_t)); + +fprintf(stderr, "_SC_PAGE_SIZE: %08lx\n", sysconf(_SC_PAGE_SIZE)); + +printf("%s:%u: x49gp: %p\n", __FUNCTION__, __LINE__, x49gp); + + INIT_LIST_HEAD(&x49gp->modules); + + + x49gp->progname = progname; + x49gp->clk_tck = sysconf(_SC_CLK_TCK); + + x49gp->emulator_fclk = 75000000; + x49gp->PCLK_ratio = 4; + x49gp->PCLK = 75000000 / 4; + +#ifdef QEMU_OLD + x49gp->env = cpu_init(); +#else + //cpu_set_log(0xffffffff); + cpu_exec_init_all(0); + x49gp->env = cpu_init("arm926"); +#endif + __GLOBAL_env = x49gp->env; + +// cpu_set_log(cpu_str_to_log_mask("all")); + + x49gp_timer_init(x49gp); + + x49gp->gtk_timer = x49gp_new_timer(X49GP_TIMER_REALTIME, + x49gp_gtk_timer, x49gp); + x49gp->lcd_timer = x49gp_new_timer(X49GP_TIMER_VIRTUAL, + x49gp_lcd_timer, x49gp); + + x49gp_ui_init(x49gp); + + x49gp_s3c2410_arm_init(x49gp); + + x49gp_flash_init(x49gp); + x49gp_sram_init(x49gp); + + x49gp_s3c2410_init(x49gp); + + if (x49gp_modules_init(x49gp)) { + exit(1); + } + + error = x49gp_modules_load(x49gp, argv[1]); + if (error) { + if (error != -EAGAIN) { + exit(1); + } + x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON); + } +// x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON); + + signal(SIGINT, ui_sighnd); + signal(SIGTERM, ui_sighnd); + signal(SIGQUIT, ui_sighnd); + + signal(SIGUSR1, arm_sighnd); + + + x49gp_set_idle(x49gp, 0); + +// stl_phys(0x08000a1c, 0x55555555); + + + x49gp_mod_timer(x49gp->gtk_timer, x49gp_get_clock()); + x49gp_mod_timer(x49gp->lcd_timer, x49gp_get_clock()); + + +#if 0 + gdbserver_start(1234); + gdb_handlesig(x49gp->env, 0); +#endif + + x49gp_main_loop(x49gp); + + + x49gp_modules_save(x49gp, argv[1]); + x49gp_modules_exit(x49gp); + + +#if 0 + printf("ClkTicks: %lu\n", ARMul_Time(x49gp->arm)); + printf("D TLB: hit0 %lu, hit1 %lu, search %lu (%lu), walk %lu\n", + x49gp->mmu->dTLB.hit0, x49gp->mmu->dTLB.hit1, + x49gp->mmu->dTLB.search, x49gp->mmu->dTLB.nsearch, + x49gp->mmu->dTLB.walk); + printf("I TLB: hit0 %lu, hit1 %lu, search %lu (%lu), walk %lu\n", + x49gp->mmu->iTLB.hit0, x49gp->mmu->iTLB.hit1, + x49gp->mmu->iTLB.search, x49gp->mmu->iTLB.nsearch, + x49gp->mmu->iTLB.walk); +#endif + return 0; +} diff --git a/module.c b/module.c new file mode 100644 index 0000000..80be789 --- /dev/null +++ b/module.c @@ -0,0 +1,456 @@ +/* $Id: module.c,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +int +x49gp_modules_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u:\n", __FUNCTION__, __LINE__); +#endif + + phys_ram_size = 0; + + list_for_each_entry(module, &x49gp->modules, list) { + error = module->init(module); + if (error) { + return error; + } + } + + phys_ram_base = mmap(0, phys_ram_size, PROT_NONE, MAP_SHARED | MAP_ANON, -1, 0); + if (phys_ram_base == (uint8_t *) -1) { + fprintf(stderr, "%s: can't mmap %08x anonymous bytes\n", + __FUNCTION__, phys_ram_size); + exit(1); + } + +printf("%s: phys_ram_base: %p\n", __FUNCTION__, phys_ram_base); + + phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); + memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); + +#ifndef QEMU_OLD + { + ram_addr_t x49gp_ram_alloc(ram_addr_t size, uint8_t *base); + x49gp_ram_alloc(phys_ram_size, phys_ram_base); + } +#endif + + return 0; +} + +int +x49gp_modules_exit(x49gp_t *x49gp) +{ + x49gp_module_t *module, *next; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u:\n", __FUNCTION__, __LINE__); +#endif + + list_for_each_entry_safe_reverse(module, next, &x49gp->modules, list) { + error = module->exit(module); + if (error) { + return error; + } + } + + return 0; +} + +int +x49gp_modules_reset(x49gp_t *x49gp, x49gp_reset_t reset) +{ + x49gp_module_t *module; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u:\n", __FUNCTION__, __LINE__); +#endif + + list_for_each_entry(module, &x49gp->modules, list) { + error = module->reset(module, reset); + if (error) { + return error; + } + } + + return 0; +} + +int +x49gp_modules_load(x49gp_t *x49gp, const char *filename) +{ + x49gp_module_t *module; + GError *gerror = NULL; + int error, result; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u:\n", __FUNCTION__, __LINE__); +#endif + + x49gp->config = g_key_file_new(); + if (NULL == x49gp->config) { + fprintf(stderr, "%s:%u: g_key_file_new: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + if (! g_key_file_load_from_file(x49gp->config, filename, 0, &gerror)) { + fprintf(stderr, "%s:%u: g_key_file_load_from_file: %s\n", + __FUNCTION__, __LINE__, gerror->message); + g_key_file_free(x49gp->config); + return -EIO; + } + + result = 0; + + list_for_each_entry(module, &x49gp->modules, list) { + error = module->load(module, x49gp->config); + if (error) { + if (error == -EAGAIN) { + result = -EAGAIN; + } else { + return error; + } + } + } + +{ + extern unsigned char *phys_ram_base; + +printf("%s: phys_ram_base: %p\n", __FUNCTION__, phys_ram_base); +printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", + phys_ram_base[0], + phys_ram_base[1], + phys_ram_base[2], + phys_ram_base[3], + phys_ram_base[4], + phys_ram_base[5], + phys_ram_base[6], + phys_ram_base[7]); +} + + return result; +} + +int +x49gp_modules_save(x49gp_t *x49gp, const char *filename) +{ + x49gp_module_t *module; + GError *gerror = NULL; + gchar *data; + gsize length; + int error; + int fd; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u:\n", __FUNCTION__, __LINE__); +#endif + + list_for_each_entry(module, &x49gp->modules, list) { + error = module->save(module, x49gp->config); + if (error) { + return error; + } + } + + data = g_key_file_to_data(x49gp->config, &length, &gerror); + if (NULL == data) { + fprintf(stderr, "%s:%u: g_key_file_to_data: %s\n", + __FUNCTION__, __LINE__, gerror->message); + return -ENOMEM; + } + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + error = -errno; + fprintf(stderr, "%s:%u: open %s: %s\n", + __FUNCTION__, __LINE__, filename, strerror(errno)); + g_free(data); + return error; + } + + + if (write(fd, data, length) != length) { + error = -errno; + fprintf(stderr, "%s:%u: write %s: %s\n", + __FUNCTION__, __LINE__, filename, strerror(errno)); + close(fd); + g_free(data); + return error; + } + + close(fd); + g_free(data); + + return 0; +} + +int +x49gp_module_register(x49gp_module_t *module) +{ + x49gp_t *x49gp = module->x49gp; + +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u: %s\n", __FUNCTION__, __LINE__, module->name); +#endif + + list_add_tail(&module->list, &x49gp->modules); + + return 0; +} + +int +x49gp_module_unregister(x49gp_module_t *module) +{ +#ifdef DEBUG_X49GP_MODULES + printf("%s:%u: %s\n", __FUNCTION__, __LINE__, module->name); +#endif + + list_del(&module->list); + + return 0; +} + +char * +x49gp_module_get_filename(x49gp_module_t *module, GKeyFile *key, + const char *name) +{ + char *filename; + char *basename; + const char *home; + char *path; + + filename = g_key_file_get_string(key, module->name, name, NULL); + if (NULL == filename) { + fprintf(stderr, "%s: %s:%u: key \"%s\" not found\n", + module->name, __FUNCTION__, __LINE__, name); + return NULL; + } + + if (g_path_is_absolute(filename)) { + return filename; + } + + home = g_get_home_dir(); + + basename = g_key_file_get_string(key, "x49gp", "basename", NULL); + if (NULL == basename) { + fprintf(stderr, "%s: %s:%u: key \"basename\" not found\n", + "x49gp", __FUNCTION__, __LINE__); + g_free(filename); + return NULL; + } + + path = g_build_filename(home, basename, filename, NULL); + if (NULL == path) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->name, __FUNCTION__, __LINE__); + } + + g_free(filename); + g_free(basename); + + return path; +} + +int +x49gp_module_get_int(x49gp_module_t *module, GKeyFile *key, const char *name, + int reset, int *valuep) +{ + uint32_t value; + int error; + + error = x49gp_module_get_u32(module, key, name, reset, &value); + if (0 == error) { + *valuep = value; + } + return error; +} + +int +x49gp_module_set_int(x49gp_module_t *module, GKeyFile *key, + const char *name, int value) +{ + char data[16]; + + snprintf(data, sizeof(data), "%d", value); + + g_key_file_set_value(key, module->name, name, data); + + return 0; +} + +int +x49gp_module_get_uint(x49gp_module_t *module, GKeyFile *key, const char *name, + unsigned int reset, unsigned int *valuep) +{ + return x49gp_module_get_u32(module, key, name, reset, valuep); +} + +int +x49gp_module_set_uint(x49gp_module_t *module, GKeyFile *key, + const char *name, unsigned int value) +{ + char data[16]; + + snprintf(data, sizeof(data), "%u", value); + + g_key_file_set_value(key, module->name, name, data); + + return 0; +} + +int +x49gp_module_get_u32(x49gp_module_t *module, GKeyFile *key, + const char *name, uint32_t reset, uint32_t *valuep) +{ + GError *gerror = NULL; + char *data, *end; + uint32_t value; + + data = g_key_file_get_value(key, module->name, name, &gerror); + if (NULL == data) { + fprintf(stderr, "%s: %s:%u: key \"%s\" not found\n", + module->name, __FUNCTION__, __LINE__, name); + *valuep = reset; + return -EAGAIN; + } + + value = strtoul(data, &end, 0); + if ((end == data) || (*end != '\0')) { + *valuep = reset; + g_free(data); + return -EAGAIN; + } + + *valuep = value; + + g_free(data); + return 0; +} + +int +x49gp_module_set_u32(x49gp_module_t *module, GKeyFile *key, + const char *name, uint32_t value) +{ + char data[16]; + + snprintf(data, sizeof(data), "0x%08x", value); + + g_key_file_set_value(key, module->name, name, data); + + return 0; +} + +int +x49gp_module_set_u64(x49gp_module_t *module, GKeyFile *key, + const char *name, uint64_t value) +{ + char data[32]; + + snprintf(data, sizeof(data), "0x%016" PRIx64 "", value); + + g_key_file_set_value(key, module->name, name, data); + + return 0; +} + +int +x49gp_module_get_u64(x49gp_module_t *module, GKeyFile *key, + const char *name, uint64_t reset, uint64_t *valuep) +{ + GError *gerror = NULL; + char *data, *end; + uint64_t value; + + data = g_key_file_get_value(key, module->name, name, &gerror); + if (NULL == data) { + fprintf(stderr, "%s: %s:%u: key \"%s\" not found\n", + module->name, __FUNCTION__, __LINE__, name); + *valuep = reset; + return -EAGAIN; + } + + value = strtoull(data, &end, 0); + if ((end == data) || (*end != '\0')) { + *valuep = reset; + g_free(data); + return -EAGAIN; + } + + *valuep = value; + + g_free(data); + return 0; +} + +int +x49gp_module_get_string(x49gp_module_t *module, GKeyFile *key, + const char *name, char *reset, char **valuep) +{ + GError *gerror = NULL; + char *data; + + data = g_key_file_get_value(key, module->name, name, &gerror); + if (NULL == data) { + fprintf(stderr, "%s: %s:%u: key \"%s\" not found\n", + module->name, __FUNCTION__, __LINE__, name); + *valuep = strdup(reset); + return -EAGAIN; + } + + *valuep = data; + return 0; +} + +int +x49gp_module_init(x49gp_t *x49gp, const char *name, + int (*init)(x49gp_module_t *), + int (*exit)(x49gp_module_t *), + int (*reset)(x49gp_module_t *, x49gp_reset_t), + int (*load)(x49gp_module_t *, GKeyFile *), + int (*save)(x49gp_module_t *, GKeyFile *), + void *user_data, x49gp_module_t **modulep) +{ + x49gp_module_t *module; + + module = malloc(sizeof(x49gp_module_t)); + if (NULL == module) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + name, __FUNCTION__, __LINE__); + return -1; + } + memset(module, 0, sizeof(x49gp_module_t)); + + module->name = name; + + module->init = init; + module->exit = exit; + module->reset = reset; + module->load = load; + module->save = save; + + module->user_data = user_data; + +// module->mutex = g_mutex_new(); + module->x49gp = x49gp; + + *modulep = module; + return 0; +} diff --git a/newconfig b/newconfig new file mode 100755 index 0000000..7050357 --- /dev/null +++ b/newconfig @@ -0,0 +1,18 @@ +#!/bin/bash + +if [ ! -r "config.tmpl" ] +then + echo "Cannot read config.tmpl" >&2 + exit 1 +fi + +B=${PWD##$HOME/} +perl -pi -e "s!^(basename=).*!\1$B!" config + +if [ "$(uname -s)" = "Linux" ] +then + perl -pi -e "s!^(filename=sdcard).dmg!\1!" config +fi + +echo "New config created" +exit 0 diff --git a/qemu/.cvsignore b/qemu/.cvsignore new file mode 100644 index 0000000..1750fe8 --- /dev/null +++ b/qemu/.cvsignore @@ -0,0 +1 @@ +qemu diff --git a/qemu/.svn/all-wcprops b/qemu/.svn/all-wcprops new file mode 100644 index 0000000..7e316fe --- /dev/null +++ b/qemu/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 30 +/p/x49gp/code/!svn/ver/10/qemu +END +prepare.sh +K 25 +svn:wc:ra_dav:version-url +V 40 +/p/x49gp/code/!svn/ver/1/qemu/prepare.sh +END +.cvsignore +K 25 +svn:wc:ra_dav:version-url +V 40 +/p/x49gp/code/!svn/ver/1/qemu/.cvsignore +END +qemu-0.9.0.tar.gz +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/1/qemu/qemu-0.9.0.tar.gz +END diff --git a/qemu/.svn/entries b/qemu/.svn/entries new file mode 100644 index 0000000..2fb1214 --- /dev/null +++ b/qemu/.svn/entries @@ -0,0 +1,139 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +patches +dir + +prepare.sh +file + + + + +2013-08-23T00:54:49.000000Z +b977fe9c9bac931baf64022487a2b1db +2008-12-11T16:48:39.837984Z +1 +antiocles +has-props + + + + + + + + + + + + + + + + + + + + +1846 + +qemu-git +dir + +CVS +dir + +.cvsignore +file + + + + +2013-08-23T00:54:49.000000Z +ac4fef8bc037aa958e4675f8c824069a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +5 + +qemu-0.9.0.tar.gz +file + + + + +2013-08-23T00:54:49.000000Z +ab11a03ba30cf4a70641f0f170473d69 +2008-12-11T16:48:39.837984Z +1 +antiocles +has-props + + + + + + + + + + + + + + + + + + + + +1901741 + diff --git a/qemu/.svn/prop-base/prepare.sh.svn-base b/qemu/.svn/prop-base/prepare.sh.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/qemu/.svn/prop-base/prepare.sh.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/qemu/.svn/prop-base/qemu-0.9.0.tar.gz.svn-base b/qemu/.svn/prop-base/qemu-0.9.0.tar.gz.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/qemu/.svn/prop-base/qemu-0.9.0.tar.gz.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/qemu/.svn/text-base/.cvsignore.svn-base b/qemu/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..1750fe8 --- /dev/null +++ b/qemu/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1 @@ +qemu diff --git a/qemu/.svn/text-base/prepare.sh.svn-base b/qemu/.svn/text-base/prepare.sh.svn-base new file mode 100644 index 0000000..c6f66cd --- /dev/null +++ b/qemu/.svn/text-base/prepare.sh.svn-base @@ -0,0 +1,61 @@ +# get/update QEMU + +# export CVS_RSH="ssh" +# cvs -z3 -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/qemu co -r "release_0_9_0" qemu + +rm -rf qemu +tar xzvf qemu-0.9.0.tar.gz +mv qemu-0.9.0 qemu + +# patch qemu sources +cd qemu + +#qemu hotfix for qcow2 +patch -p0 -u < ../patches/qemu-0.9.0-qcow2.diff + +#qemu gcc4 patches +patch -p1 -u < ../patches/qemu-0.9.0-gcc4.patch +patch -p1 -u < ../patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch +patch -p1 -u < ../patches/qemu-0.7.2-gcc4-opts.patch +patch -p1 -u < ../patches/qemu-0.8.0-gcc4-hacks.patch + +#qemu OS X86 patches +patch -p1 -u < ../patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch +patch -p1 -u -f < ../patches/qemu-0.9.0-i386-FORCE_RET.patch +patch -p1 -u < ../patches/qemu-0.9.0-osx-intel-port.patch + +patch -p1 -u < ../patches/qemu-0.8.0-osx-bugfix.patch + +# arm patches +patch -p1 -u < ../patches/qemu-0.9.0-arm-shift.patch + +# x49gp patches +patch -p1 -u < ../patches/qemu-0.9.0-sparc-compile-flags.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-load-store-le.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-clobber.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-register.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-dump-state.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-mmu.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-semihosting.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-debug-unassigned.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-block.patch + +# only build libqemu.a +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-build-libqemu.patch + + +# configure +if [ "`uname -m`" = "sparc64" ]; then + STUB=sparc32 +fi + +if [ "`uname -s`" = "Darwin" ]; then + OPTIONS="--disable-gcc-check" +fi + +OPTIONS="${OPTIONS} --disable-gfx-check" + +${STUB} ./configure ${OPTIONS} --target-list=arm-softmmu + +cd .. diff --git a/qemu/.svn/text-base/qemu-0.9.0.tar.gz.svn-base b/qemu/.svn/text-base/qemu-0.9.0.tar.gz.svn-base new file mode 100644 index 0000000..07f9ce7 Binary files /dev/null and b/qemu/.svn/text-base/qemu-0.9.0.tar.gz.svn-base differ diff --git a/qemu/CVS/.svn/all-wcprops b/qemu/CVS/.svn/all-wcprops new file mode 100644 index 0000000..df1b5d4 --- /dev/null +++ b/qemu/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 33 +/p/x49gp/code/!svn/ver/1/qemu/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 44 +/p/x49gp/code/!svn/ver/1/qemu/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 38 +/p/x49gp/code/!svn/ver/1/qemu/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/qemu/CVS/Entries +END diff --git a/qemu/CVS/.svn/entries b/qemu/CVS/.svn/entries new file mode 100644 index 0000000..c36337e --- /dev/null +++ b/qemu/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/CVS +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +Repository +file + + + + +2013-08-23T00:54:48.000000Z +5d8d42b74105fbc8bc3df8ddc315affd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +11 + +Root +file + + + + +2013-08-23T00:54:48.000000Z +f51b768066a9e7d88829b19678326fcd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +60 + +Entries +file + + + + +2013-08-23T00:54:48.000000Z +d867c060f2bf9401f0d359cb587600a6 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +150 + diff --git a/qemu/CVS/.svn/text-base/Entries.svn-base b/qemu/CVS/.svn/text-base/Entries.svn-base new file mode 100644 index 0000000..bab072d --- /dev/null +++ b/qemu/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,4 @@ +/.cvsignore/1.1/Thu Dec 11 12:22:06 2008// +/prepare.sh/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0.tar.gz/1.1/Thu Dec 11 12:14:08 2008// +D/patches//// diff --git a/qemu/CVS/.svn/text-base/Repository.svn-base b/qemu/CVS/.svn/text-base/Repository.svn-base new file mode 100644 index 0000000..1275b0c --- /dev/null +++ b/qemu/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +x49gp/qemu diff --git a/qemu/CVS/.svn/text-base/Root.svn-base b/qemu/CVS/.svn/text-base/Root.svn-base new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/qemu/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/qemu/CVS/Entries b/qemu/CVS/Entries new file mode 100644 index 0000000..bab072d --- /dev/null +++ b/qemu/CVS/Entries @@ -0,0 +1,4 @@ +/.cvsignore/1.1/Thu Dec 11 12:22:06 2008// +/prepare.sh/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0.tar.gz/1.1/Thu Dec 11 12:14:08 2008// +D/patches//// diff --git a/qemu/CVS/Repository b/qemu/CVS/Repository new file mode 100644 index 0000000..1275b0c --- /dev/null +++ b/qemu/CVS/Repository @@ -0,0 +1 @@ +x49gp/qemu diff --git a/qemu/CVS/Root b/qemu/CVS/Root new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/qemu/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/qemu/patches/.svn/all-wcprops b/qemu/patches/.svn/all-wcprops new file mode 100644 index 0000000..c35b488 --- /dev/null +++ b/qemu/patches/.svn/all-wcprops @@ -0,0 +1,161 @@ +K 25 +svn:wc:ra_dav:version-url +V 37 +/p/x49gp/code/!svn/ver/1/qemu/patches +END +qemu-0.9.0-enforce-16byte-stack-boundary.patch +K 25 +svn:wc:ra_dav:version-url +V 84 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch +END +q_block.c_hdled_1.diff +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/1/qemu/patches/q_block.c_hdled_1.diff +END +qemu-0.9.0-sparc-load-store-le.patch +K 25 +svn:wc:ra_dav:version-url +V 74 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-sparc-load-store-le.patch +END +qemu-0.9.0-sparc-clobber.patch +K 25 +svn:wc:ra_dav:version-url +V 68 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-sparc-clobber.patch +END +qemu-0.9.0-x49gp-arm-semihosting.patch +K 25 +svn:wc:ra_dav:version-url +V 76 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-arm-semihosting.patch +END +qemu-0.9.0-gcc4.patch +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-gcc4.patch +END +q_vga.c_02.diff +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/1/qemu/patches/q_vga.c_02.diff +END +q_host-cocoa_02.diff +K 25 +svn:wc:ra_dav:version-url +V 58 +/p/x49gp/code/!svn/ver/1/qemu/patches/q_host-cocoa_02.diff +END +qemu-0.9.0-x49gp-arm-mmu.patch +K 25 +svn:wc:ra_dav:version-url +V 68 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-arm-mmu.patch +END +qemu-0.9.0-sparc-compile-flags.patch +K 25 +svn:wc:ra_dav:version-url +V 74 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-sparc-compile-flags.patch +END +qemu-0.9.0-arm-shift.patch +K 25 +svn:wc:ra_dav:version-url +V 64 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-arm-shift.patch +END +qemu-0.8.0-osx-bugfix.patch +K 25 +svn:wc:ra_dav:version-url +V 65 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.8.0-osx-bugfix.patch +END +qemu-0.9.0-sparc-register.patch +K 25 +svn:wc:ra_dav:version-url +V 69 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-sparc-register.patch +END +qemu-0.7.2-dyngen-check-stack-clobbers.patch +K 25 +svn:wc:ra_dav:version-url +V 82 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch +END +q_block_int.h_hdled_1.diff +K 25 +svn:wc:ra_dav:version-url +V 64 +/p/x49gp/code/!svn/ver/1/qemu/patches/q_block_int.h_hdled_1.diff +END +qemu-0.9.0-x49gp-debug-unassigned.patch +K 25 +svn:wc:ra_dav:version-url +V 77 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-debug-unassigned.patch +END +qemu-0.9.0-i386-FORCE_RET.patch +K 25 +svn:wc:ra_dav:version-url +V 69 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-i386-FORCE_RET.patch +END +qemu-2ndbootdevice_04.diff +K 25 +svn:wc:ra_dav:version-url +V 64 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-2ndbootdevice_04.diff +END +qemu-0.7.2-gcc4-opts.patch +K 25 +svn:wc:ra_dav:version-url +V 64 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.7.2-gcc4-opts.patch +END +qemu-0.9.0-x49gp-block.patch +K 25 +svn:wc:ra_dav:version-url +V 66 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-block.patch +END +qemu-0.9.0-qcow2.diff +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-qcow2.diff +END +qemu-0.9.0-osx-intel-port.patch +K 25 +svn:wc:ra_dav:version-url +V 69 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-osx-intel-port.patch +END +qemu-0.9.0-x49gp-build-libqemu.patch +K 25 +svn:wc:ra_dav:version-url +V 74 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-build-libqemu.patch +END +qemu-0.8.0-gcc4-hacks.patch +K 25 +svn:wc:ra_dav:version-url +V 65 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.8.0-gcc4-hacks.patch +END +qemu-0.9.0-x49gp-phys_ram_dirty.patch +K 25 +svn:wc:ra_dav:version-url +V 75 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch +END +qemu-0.9.0-x49gp-arm-dump-state.patch +K 25 +svn:wc:ra_dav:version-url +V 75 +/p/x49gp/code/!svn/ver/1/qemu/patches/qemu-0.9.0-x49gp-arm-dump-state.patch +END diff --git a/qemu/patches/.svn/entries b/qemu/patches/.svn/entries new file mode 100644 index 0000000..dd37aab --- /dev/null +++ b/qemu/patches/.svn/entries @@ -0,0 +1,915 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/patches +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +qemu-0.9.0-enforce-16byte-stack-boundary.patch +file + + + + +2013-08-23T00:54:47.000000Z +acf5b2d578edd44a23662a82f6f7202b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +605 + +q_block.c_hdled_1.diff +file + + + + +2013-08-23T00:54:47.000000Z +df754cafc494f704d5ad15d86e158c98 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1031 + +qemu-0.9.0-sparc-load-store-le.patch +file + + + + +2013-08-23T00:54:47.000000Z +8f3bfec7c2e4986f57f9dbab690b4c12 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +2033 + +qemu-0.9.0-sparc-clobber.patch +file + + + + +2013-08-23T00:54:47.000000Z +587e863673d71680c6487efe60f72936 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +556 + +qemu-0.9.0-x49gp-arm-semihosting.patch +file + + + + +2013-08-23T00:54:47.000000Z +16ed1d0648c25b23c266bd384a42701b +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1828 + +qemu-0.9.0-gcc4.patch +file + + + + +2013-08-23T00:54:47.000000Z +5675fd722c1b751c5299f890340c415f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +29177 + +q_vga.c_02.diff +file + + + + +2013-08-23T00:54:47.000000Z +791d3bba6c7f8ef34f77462c67388492 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1093 + +q_host-cocoa_02.diff +file + + + + +2013-08-23T00:54:47.000000Z +4a451861d89d0fd5e76b42ece94906f7 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1142 + +qemu-0.9.0-x49gp-arm-mmu.patch +file + + + + +2013-08-23T00:54:47.000000Z +82f4b18f726fe7178c8cec9fb4d0b043 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +5440 + +CVS +dir + +qemu-0.9.0-sparc-compile-flags.patch +file + + + + +2013-08-23T00:54:47.000000Z +7679bd8ea518268cc2201bcbd97e8481 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +951 + +qemu-0.9.0-arm-shift.patch +file + + + + +2013-08-23T00:54:47.000000Z +e0a8ec861adc7e8df06161708b4d1126 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +529 + +qemu-0.8.0-osx-bugfix.patch +file + + + + +2013-08-23T00:54:47.000000Z +64c0227916144b58ee069e3d62283d48 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +5038 + +qemu-0.9.0-sparc-register.patch +file + + + + +2013-08-23T00:54:47.000000Z +32cd5600e54cb4ccb669438f381e652f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +5936 + +qemu-0.7.2-dyngen-check-stack-clobbers.patch +file + + + + +2013-08-23T00:54:47.000000Z +88fd85405713717ef7c239acfa4720f0 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +4516 + +q_block_int.h_hdled_1.diff +file + + + + +2013-08-23T00:54:47.000000Z +9fbaf47448fe6ff7eabc551d0bf5a3eb +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +493 + +qemu-0.9.0-x49gp-debug-unassigned.patch +file + + + + +2013-08-23T00:54:47.000000Z +7e05768e2144bb5055ff16a6bbfeb5c5 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +909 + +qemu-0.9.0-i386-FORCE_RET.patch +file + + + + +2013-08-23T00:54:47.000000Z +d9b5d250c6c239516ea72464a7a6fd06 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +703 + +qemu-2ndbootdevice_04.diff +file + + + + +2013-08-23T00:54:47.000000Z +1a7f4c0dfeb82204f1e987285de3d440 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +6157 + +qemu-0.7.2-gcc4-opts.patch +file + + + + +2013-08-23T00:54:47.000000Z +aaa22a7297ac7685cb462e3ec1668e79 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1616 + +qemu-0.9.0-x49gp-block.patch +file + + + + +2013-08-23T00:54:47.000000Z +2138e51df5a9fea7098a29c8ab7c4b58 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +38156 + +qemu-0.9.0-qcow2.diff +file + + + + +2013-08-23T00:54:47.000000Z +59883b1fd909746e532927f47cfd7061 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +884 + +qemu-0.9.0-osx-intel-port.patch +file + + + + +2013-08-23T00:54:47.000000Z +7e6cce97c25af531e7cf4e5a3a1e8e04 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +10969 + +qemu-0.9.0-x49gp-build-libqemu.patch +file + + + + +2013-08-23T00:54:47.000000Z +8665c63675486d20b8c035298f73867a +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +371 + +qemu-0.8.0-gcc4-hacks.patch +file + + + + +2013-08-23T00:54:47.000000Z +cb2b0532b6eab6f80c14b33cfba70662 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +4451 + +qemu-0.9.0-x49gp-phys_ram_dirty.patch +file + + + + +2013-08-23T00:54:47.000000Z +d1ad97167cb5ed3c5d17a442df8f1cf0 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +716 + +qemu-0.9.0-x49gp-arm-dump-state.patch +file + + + + +2013-08-23T00:54:47.000000Z +10ada64a65b131f0dc269591f481f539 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1012 + diff --git a/qemu/patches/.svn/text-base/q_block.c_hdled_1.diff.svn-base b/qemu/patches/.svn/text-base/q_block.c_hdled_1.diff.svn-base new file mode 100644 index 0000000..ad53ba8 --- /dev/null +++ b/qemu/patches/.svn/text-base/q_block.c_hdled_1.diff.svn-base @@ -0,0 +1,34 @@ +--- block.c 2007-02-06 02:15:39.000000000 +0100 ++++ block2.c 2007-02-06 02:24:10.000000000 +0100 +@@ -497,6 +497,7 @@ + int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) +@@ -534,6 +535,7 @@ + int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + if (!bs->drv) + return -ENOMEDIUM; +@@ -1058,6 +1060,7 @@ + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) +@@ -1078,6 +1081,7 @@ + const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) diff --git a/qemu/patches/.svn/text-base/q_block_int.h_hdled_1.diff.svn-base b/qemu/patches/.svn/text-base/q_block_int.h_hdled_1.diff.svn-base new file mode 100644 index 0000000..835d7fb --- /dev/null +++ b/qemu/patches/.svn/text-base/q_block_int.h_hdled_1.diff.svn-base @@ -0,0 +1,10 @@ +--- block_int.h 2006-06-21 18:46:53.000000000 +0200 ++++ block_int2.h 2006-07-03 17:20:04.000000000 +0200 +@@ -51,6 +51,7 @@ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ ++ int activityLED; /* if true, the media is accessed atm */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; diff --git a/qemu/patches/.svn/text-base/q_host-cocoa_02.diff.svn-base b/qemu/patches/.svn/text-base/q_host-cocoa_02.diff.svn-base new file mode 100644 index 0000000..0423bba --- /dev/null +++ b/qemu/patches/.svn/text-base/q_host-cocoa_02.diff.svn-base @@ -0,0 +1,26 @@ +--- Makefile.target 2007-01-31 13:24:18.000000000 +0100 ++++ Makefile.target 2007-02-02 14:45:02.000000000 +0100 +@@ -415,8 +419,8 @@ + endif + VL_OBJS+=vnc.o + ifdef CONFIG_COCOA +-VL_OBJS+=cocoa.o +-COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit ++VL_OBJS+=cocoaQemuMain.o cocoaQemuController.o cocoaQemu.o cocoaQemuProgressWindow.o cocoaQemuWindow.o cocoaQemuOpenGLView.o cocoaQemuQuartzView.o cocoaQemuQuickDrawView.o cocoaPopUpView.o cocoaCpuView.o FSController.o FSRoundedView.o FSToolbarController.o FSTransparentButton.o ++COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit -framework CoreFoundation -framework OpenGL -framework ApplicationServices + ifdef CONFIG_COREAUDIO + COCOA_LIBS+=-framework CoreAudio + endif +@@ -465,7 +469,11 @@ + $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) + +-cocoa.o: cocoa.m ++ ++cocoa%.o: host-cocoa/cocoa%.m ++ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< ++ ++FS%.o: host-cocoa/FSControls/FS%.m + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + + sdl.o: sdl.c keymaps.c sdl_keysym.h diff --git a/qemu/patches/.svn/text-base/q_vga.c_02.diff.svn-base b/qemu/patches/.svn/text-base/q_vga.c_02.diff.svn-base new file mode 100644 index 0000000..1eb4e28 --- /dev/null +++ b/qemu/patches/.svn/text-base/q_vga.c_02.diff.svn-base @@ -0,0 +1,41 @@ +--- vga.c 2005-12-19 23:51:53.000000000 +0100 ++++ vga2.c 2006-04-10 20:21:56.000000000 +0200 +@@ -788,22 +788,38 @@ + + static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 5) << 5) | ((g >> 5) << 2) | (r >> 6); ++#else + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); ++#endif + } + + static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); ++#else + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); ++#endif + } + + static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); ++#else + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); ++#endif + } + + static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return (b << 16) | (g << 8) | r; ++#else + return (r << 16) | (g << 8) | b; ++#endif + } + + #define DEPTH 8 diff --git a/qemu/patches/.svn/text-base/qemu-0.7.2-dyngen-check-stack-clobbers.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.7.2-dyngen-check-stack-clobbers.patch.svn-base new file mode 100644 index 0000000..8743037 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.7.2-dyngen-check-stack-clobbers.patch.svn-base @@ -0,0 +1,137 @@ +2005-11-11 Gwenole Beauchesne + + * Check for stack clobbers in functions using GOTO_LABEL_PARAM(). + +--- qemu-0.7.2/dyngen.c.dyngen-check-stack-clobbers 2005-11-11 16:26:33.000000000 +0100 ++++ qemu-0.7.2/dyngen.c 2005-11-11 17:30:29.000000000 +0100 +@@ -1414,6 +1414,9 @@ int arm_emit_ldr_info(const char *name, + #define FLAG_TARGET (1 << 3) + /* This is a magic instruction that needs fixing up. */ + #define FLAG_EXIT (1 << 4) ++/* This instruction clobbers the stack pointer. */ ++/* XXX only supports push, pop, add/sub $imm,%esp */ ++#define FLAG_STACK (1 << 5) + #define MAX_EXITS 5 + + static void +@@ -1454,6 +1457,7 @@ trace_i386_insn (const char *name, uint8 + int is_jmp; + int is_exit; + int is_pcrel; ++ int is_stack; + int immed; + int seen_rexw; + int32_t disp; +@@ -1476,6 +1480,7 @@ trace_i386_insn (const char *name, uint8 + is_exit = 0; + seen_rexw = 0; + is_pcrel = 0; ++ is_stack = 0; + + while (is_prefix) { + op = ptr[insn_size]; +@@ -1522,6 +1527,7 @@ trace_i386_insn (const char *name, uint8 + switch (op & 0x7) { + case 0: /* push fs/gs */ + case 1: /* pop fs/gs */ ++ is_stack = 1; + case 2: /* cpuid/rsm */ + modrm = 0; + break; +@@ -1594,6 +1600,7 @@ trace_i386_insn (const char *name, uint8 + #endif + case 5: /* push/pop general register. */ + modrm = 0; ++ is_stack = 1; + break; + + case 6: +@@ -1601,6 +1608,7 @@ trace_i386_insn (const char *name, uint8 + case 0: /* pusha */ + case 1: /* popa */ + modrm = 0; ++ is_stack = 1; + break; + case 2: /* bound */ + case 3: /* arpl */ +@@ -1620,10 +1628,12 @@ trace_i386_insn (const char *name, uint8 + case 8: /* push immediate */ + immed = op_size; + modrm = 0; ++ is_stack = 1; + break; + case 10: /* push 8-bit immediate */ + immed = 1; + modrm = 0; ++ is_stack = 1; + break; + case 9: /* imul immediate */ + immed = op_size; +@@ -1653,8 +1663,22 @@ trace_i386_insn (const char *name, uint8 + immed = op_size; + else + immed = 1; ++ if (op == 0x81 || op == 0x83) { ++ /* add, sub */ ++ op = ptr[insn_size]; ++ switch ((op >> 3) & 7) { ++ case 0: ++ case 5: ++ is_stack = (op & 7) == 4; ++ break; ++ } ++ } + } +- /* else test, xchg, mov, lea or pop general. */ ++ else if ((op & 0xf) == 0xf) { ++ /* pop general. */ ++ is_stack = 1; ++ } ++ /* else test, xchg, mov, lea. */ + break; + + case 9: +@@ -1904,6 +1928,9 @@ trace_i386_insn (const char *name, uint8 + if (is_exit) + flags[insn] |= FLAG_EXIT; + ++ if (is_stack) ++ flags[insn] |= FLAG_STACK; ++ + if (!(is_jmp || is_ret || is_exit)) + flags[insn + insn_size] |= FLAG_INSN; + } +@@ -1924,6 +1951,7 @@ static int trace_i386_op(const char * na + int num_exits; + int len; + int last_insn; ++ int stack_clobbered; + + len = *plen; + flags = malloc(len + 1); +@@ -1947,6 +1975,7 @@ static int trace_i386_op(const char * na + retpos = -1; + num_exits = 0; + last_insn = 0; ++ stack_clobbered = 0; + for (insn = 0; insn < len; insn++) { + if (flags[insn] & FLAG_RET) { + /* ??? In theory it should be possible to handle multiple return +@@ -1956,6 +1985,8 @@ static int trace_i386_op(const char * na + retpos = insn; + } + if (flags[insn] & FLAG_EXIT) { ++ if (stack_clobbered) ++ error("Stack clobbered in %s", name); + if (num_exits == MAX_EXITS) + error("Too many block exits in %s", name); + exit_addrs[num_exits] = insn; +@@ -1963,6 +1994,8 @@ static int trace_i386_op(const char * na + } + if (flags[insn] & FLAG_INSN) + last_insn = insn; ++ if (flags[insn] & FLAG_STACK) ++ stack_clobbered = 1; + } + + exit_addrs[num_exits] = -1; diff --git a/qemu/patches/.svn/text-base/qemu-0.7.2-gcc4-opts.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.7.2-gcc4-opts.patch.svn-base new file mode 100644 index 0000000..ce5e3aa --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.7.2-gcc4-opts.patch.svn-base @@ -0,0 +1,37 @@ +2005-11-11 Gwenole Beauchesne + + * Globaaly save %ebx, %esi, %edi on entry to generated + function. This avoids some register spills in synthetic opcodes. + NOTE: this also easily fixes gcc4 compiled qemu-system-x86_64 on x86. + +--- qemu-0.7.2/cpu-exec.c.gcc4-opts 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/cpu-exec.c 2005-11-11 17:40:47.000000000 +0100 +@@ -561,6 +561,15 @@ int cpu_exec(CPUState *env1) + : /* no outputs */ + : "r" (gen_func) + : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); ++#elif defined(TARGET_X86_64) && defined(__i386__) ++ asm volatile ("push %%ebx\n" ++ "push %%esi\n" ++ "push %%edi\n" ++ "call *%0\n" ++ "pop %%edi\n" ++ "pop %%esi\n" ++ "pop %%ebx\n" ++ : : "r" (gen_func) : "ebx", "esi", "edi"); + #elif defined(TARGET_I386) && defined(USE_CODE_COPY) + { + if (!(tb->cflags & CF_CODE_COPY)) { +--- qemu-0.7.2/Makefile.target.gcc4-opts 2005-11-11 16:26:33.000000000 +0100 ++++ qemu-0.7.2/Makefile.target 2005-11-11 17:59:56.000000000 +0100 +@@ -65,6 +65,10 @@ OP_CFLAGS+= -falign-functions=0 -fno-gcs + else + OP_CFLAGS+= -malign-functions=0 + endif ++ifeq ($(TARGET_ARCH), x86_64) ++# XXX globally save %ebx, %esi, %edi on entry to generated function ++OP_CFLAGS+= -fcall-used-ebx -fcall-used-esi -fcall-used-edi ++endif + + ifdef TARGET_GPROF + USE_I386_LD=y diff --git a/qemu/patches/.svn/text-base/qemu-0.8.0-gcc4-hacks.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.8.0-gcc4-hacks.patch.svn-base new file mode 100644 index 0000000..f7cbdcf --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.8.0-gcc4-hacks.patch.svn-base @@ -0,0 +1,118 @@ +2005-10-28 Gwenole Beauchesne + + * Various additional hacks for GCC4. + +--- qemu-0.7.2/target-i386/ops_sse.h.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/target-i386/ops_sse.h 2005-10-28 10:09:21.000000000 +0200 +@@ -34,6 +34,12 @@ + #define Q(n) XMM_Q(n) + #define SUFFIX _xmm + #endif ++#if defined(__i386__) && __GNUC__ >= 4 ++#define RegCopy(d, s) __builtin_memcpy(&(d), &(s), sizeof(d)) ++#endif ++#ifndef RegCopy ++#define RegCopy(d, s) d = s ++#endif + + void OPPROTO glue(op_psrlw, SUFFIX)(void) + { +@@ -570,7 +576,7 @@ void OPPROTO glue(op_pshufw, SUFFIX) (vo + r.W(1) = s->W((order >> 2) & 3); + r.W(2) = s->W((order >> 4) & 3); + r.W(3) = s->W((order >> 6) & 3); +- *d = r; ++ RegCopy(*d, r); + } + #else + void OPPROTO op_shufps(void) +--- qemu-0.7.2/target-i386/helper.c.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/target-i386/helper.c 2005-10-28 10:09:21.000000000 +0200 +@@ -3130,8 +3130,15 @@ void helper_fxrstor(target_ulong ptr, in + nb_xmm_regs = 8 << data64; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { ++#if defined(__i386__) && __GNUC__ >= 4 ++ env->xmm_regs[i].XMM_L(0) = ldl(addr); ++ env->xmm_regs[i].XMM_L(1) = ldl(addr + 4); ++ env->xmm_regs[i].XMM_L(2) = ldl(addr + 8); ++ env->xmm_regs[i].XMM_L(3) = ldl(addr + 12); ++#else + env->xmm_regs[i].XMM_Q(0) = ldq(addr); + env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); ++#endif + addr += 16; + } + } +--- qemu-0.7.2/cpu-all.h.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/cpu-all.h 2005-10-28 10:09:21.000000000 +0200 +@@ -339,7 +339,13 @@ + + static inline void stq_le_p(void *ptr, uint64_t v) + { ++#if defined(__i386__) && __GNUC__ >= 4 ++ const union { uint64_t v; uint32_t p[2]; } x = { .v = v }; ++ ((uint32_t *)ptr)[0] = x.p[0]; ++ ((uint32_t *)ptr)[1] = x.p[1]; ++#else + *(uint64_t *)ptr = v; ++#endif + } + + /* float access */ +--- qemu-0.7.2/softmmu_header.h.gcc4-hacks 2005-10-28 10:08:08.000000000 +0200 ++++ qemu-0.7.2/softmmu_header.h 2005-10-28 10:09:21.000000000 +0200 +@@ -104,7 +104,7 @@ + void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user); + + #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ +- (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) ++ (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) && (__GNUC__ < 4) + + #define CPU_TLB_ENTRY_BITS 4 + +@@ -131,7 +131,7 @@ static inline RES_TYPE glue(glue(ld, USU + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + return res; + } + +@@ -178,13 +178,14 @@ static inline int glue(glue(lds, SUFFIX) + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + return res; + } + #endif + +-static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) ++static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE val) + { ++ RES_TYPE v = val; + asm volatile ("movl %0, %%edx\n" + "movl %0, %%eax\n" + "shrl %3, %%edx\n" +@@ -236,16 +237,14 @@ + "2:\n" + : + : "r" (ptr), +-/* NOTE: 'q' would be needed as constraint, but we could not use it +- with T1 ! */ +- "r" (v), ++ "q" (v), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + } + + /* TODO: handle 64-bit access sizes and addresses */ diff --git a/qemu/patches/.svn/text-base/qemu-0.8.0-osx-bugfix.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.8.0-osx-bugfix.patch.svn-base new file mode 100644 index 0000000..a04c0f5 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.8.0-osx-bugfix.patch.svn-base @@ -0,0 +1,155 @@ +--- qemu-0.8.0/target-i386/helper.c.osx-bugfix 2006-03-17 14:19:42.000000000 +0900 ++++ qemu-0.8.0/target-i386/helper.c 2006-03-17 07:27:57.000000000 +0900 +@@ -28,68 +28,6 @@ do {\ + (raise_exception_err)(a, b);\ + } while (0) + #endif +- +-const uint8_t parity_table[256] = { +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +-}; +- +-/* modulo 17 table */ +-const uint8_t rclw_table[32] = { +- 0, 1, 2, 3, 4, 5, 6, 7, +- 8, 9,10,11,12,13,14,15, +- 16, 0, 1, 2, 3, 4, 5, 6, +- 7, 8, 9,10,11,12,13,14, +-}; +- +-/* modulo 9 table */ +-const uint8_t rclb_table[32] = { +- 0, 1, 2, 3, 4, 5, 6, 7, +- 8, 0, 1, 2, 3, 4, 5, 6, +- 7, 8, 0, 1, 2, 3, 4, 5, +- 6, 7, 8, 0, 1, 2, 3, 4, +-}; +- +-const CPU86_LDouble f15rk[7] = +-{ +- 0.00000000000000000000L, +- 1.00000000000000000000L, +- 3.14159265358979323851L, /*pi*/ +- 0.30102999566398119523L, /*lg2*/ +- 0.69314718055994530943L, /*ln2*/ +- 1.44269504088896340739L, /*l2e*/ +- 3.32192809488736234781L, /*l2t*/ +-}; + + /* thread support */ + +--- qemu-0.8.0/target-i386/op.c.osx-bugfix 2006-03-17 14:20:37.000000000 +0900 ++++ qemu-0.8.0/target-i386/op.c 2006-03-17 07:28:40.000000000 +0900 +@@ -21,19 +21,69 @@ + #define ASM_SOFTMMU + #include "exec.h" + +-#if defined(__APPLE__) +-/* XXX avoid indirect symbols, correct address patched at code generation time. */ +-static const uint8_t parity_table[256]; +-static const uint8_t rclw_table[32]; +-static const uint8_t rclb_table[32]; +-static const CPU86_LDouble f15rk[7]; +-#else +-extern const uint8_t parity_table[256]; +-extern const uint8_t rclw_table[32]; +-extern const uint8_t rclb_table[32]; +-extern const CPU86_LDouble f15rk[7]; +-#endif ++const uint8_t parity_table[256] = { ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++}; + ++/* modulo 17 table */ ++const uint8_t rclw_table[32] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 9,10,11,12,13,14,15, ++ 16, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 9,10,11,12,13,14, ++}; ++ ++/* modulo 9 table */ ++const uint8_t rclb_table[32] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 0, 1, 2, 3, 4, ++}; ++ ++const CPU86_LDouble f15rk[7] = ++{ ++ 0.00000000000000000000L, ++ 1.00000000000000000000L, ++ 3.14159265358979323851L, /*pi*/ ++ 0.30102999566398119523L, /*lg2*/ ++ 0.69314718055994530943L, /*ln2*/ ++ 1.44269504088896340739L, /*l2e*/ ++ 3.32192809488736234781L, /*l2t*/ ++}; ++ ++ + /* n must be a constant to be efficient */ + static inline target_long lshift(target_long x, int n) + { diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-arm-shift.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-arm-shift.patch.svn-base new file mode 100644 index 0000000..810f232 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-arm-shift.patch.svn-base @@ -0,0 +1,20 @@ +--- qemu-0.9.0/target-arm/op.c 2007-07-23 06:57:25.000000000 +0200 ++++ qemu/target-arm/op.c 2007-07-23 06:58:25.000000000 +0200 +@@ -819,7 +819,7 @@ + int shift; + shift = PARAM1; + if (shift != 0) { +- env->CF = (T1 >> (32 - shift)) & 1; ++ env->CF = (T0 >> (32 - shift)) & 1; + T0 = T0 << shift; + } + env->NZF = T0; +@@ -832,7 +832,7 @@ + + shift = PARAM1; + if (shift == 0) { +- env->CF = ((uint32_t)shift) >> 31; ++ env->CF = ((uint32_t)T0) >> 31; + T0 = 0; + } else { + env->CF = (T0 >> (shift - 1)) & 1; diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-enforce-16byte-stack-boundary.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-enforce-16byte-stack-boundary.patch.svn-base new file mode 100644 index 0000000..65aaaf1 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-enforce-16byte-stack-boundary.patch.svn-base @@ -0,0 +1,19 @@ +2007-02-01 Mike kronenberg + + * Fix for QEMU 0.9.0. + +2006-02-12 Gwenole Beauchesne + + * Enforce 16-byte boundaries. + +--- qemu-0.8.0/Makefile.target.enforce-16byte-stack-boundary 2006-02-12 17:46:54.000000000 +0100 ++++ qemu-0.8.0/Makefile.target 2006-02-12 17:55:24.000000000 +0100 +@@ -67,7 +67,7 @@ endif + + ifeq ($(ARCH),i386) + HELPER_CFLAGS+=-fomit-frame-pointer +-OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer ++OP_CFLAGS+=-fomit-frame-pointer + ifeq ($(HAVE_GCC3_OPTIONS),yes) + OP_CFLAGS+= -falign-functions=0 -fno-gcse + else diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-gcc4.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-gcc4.patch.svn-base new file mode 100644 index 0000000..5eca38b --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-gcc4.patch.svn-base @@ -0,0 +1,892 @@ +2007-02-01 Mike Kronenberg + + * target-ppc/exec.h: Fix for QEMU 0.9.0. + * dyngen-exec.h: Fix for QEMU 0.9.0. + +2005-06-02 Gwenole Beauchesne + + * dyngen.c (trace_i386_insn): Fix push/imul case with 8-bit + immediate. + +2005-05-11 Paul Brook + + * gcc4 host support. + +--- qemu-0.7.0/target-ppc/exec.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/target-ppc/exec.h 2005-06-02 21:41:51.000000000 +0200 +@@ -33,11 +33,7 @@ #define FT0 (env->ft0) + #define FT1 (env->ft1) + #define FT2 (env->ft2) + +-#if defined (DEBUG_OP) +-# define RETURN() __asm__ __volatile__("nop" : : : "memory"); +-#else +-# define RETURN() __asm__ __volatile__("" : : : "memory"); +-#endif ++#define RETURN() FORCE_RET() + + #include "cpu.h" + #include "exec-all.h" +--- qemu-0.7.0/dyngen-exec.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/dyngen-exec.h 2005-06-02 21:41:51.000000000 +0200 +@@ -155,7 +155,12 @@ extern int printf(const char *, ...); + #endif + + /* force GCC to generate only one epilog at the end of the function */ ++#if defined(__i386__) || defined(__x86_64__) ++/* Also add 4 bytes of padding so that we can replace the ret with a jmp. */ ++#define FORCE_RET() asm volatile ("nop;nop;nop;nop"); ++#else + #define FORCE_RET() __asm__ __volatile__("" : : : "memory"); ++#endif + + #ifndef OPPROTO + #define OPPROTO +@@ -205,12 +210,19 @@ extern int __op_jmp0, __op_jmp1, __op_jm + #endif + + #ifdef __i386__ +-#define EXIT_TB() asm volatile ("ret") +-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) ++/* Dyngen will replace hlt instructions with a ret instruction. Inserting a ++ ret directly would confuse dyngen. */ ++#define EXIT_TB() asm volatile ("hlt") ++/* Dyngen will replace cli with 0x9e (jmp). ++ We generate the offset manually. */ ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif + #ifdef __x86_64__ +-#define EXIT_TB() asm volatile ("ret") +-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) ++/* The same as i386. */ ++#define EXIT_TB() asm volatile ("hlt") ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif + #ifdef __powerpc__ + #define EXIT_TB() asm volatile ("blr") +--- qemu-0.7.0/dyngen.c.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/dyngen.c 2005-06-02 22:25:06.000000000 +0200 +@@ -32,6 +32,8 @@ + + #include "config-host.h" + ++//#define DEBUG_OP ++ + /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross + compilation */ + #if defined(CONFIG_WIN32) +@@ -1343,6 +1345,644 @@ int arm_emit_ldr_info(const char *name, + #endif + + ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ ++/* This byte is the first byte of an instruction. */ ++#define FLAG_INSN (1 << 0) ++/* This byte has been processed as part of an instruction. */ ++#define FLAG_SCANNED (1 << 1) ++/* This instruction is a return instruction. Gcc cometimes generates prefix ++ bytes, so may be more than one byte long. */ ++#define FLAG_RET (1 << 2) ++/* This is either the target of a jump, or the preceeding instruction uses ++ a pc-relative offset. */ ++#define FLAG_TARGET (1 << 3) ++/* This is a magic instruction that needs fixing up. */ ++#define FLAG_EXIT (1 << 4) ++#define MAX_EXITS 5 ++ ++static void ++bad_opcode(const char *name, uint32_t op) ++{ ++ error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name); ++} ++ ++/* Mark len bytes as scanned, Returns insn_size + len. Reports an error ++ if these bytes have already been scanned. */ ++static int ++eat_bytes(const char *name, char *flags, int insn, int insn_size, int len) ++{ ++ while (len > 0) { ++ /* This should never occur in sane code. */ ++ if (flags[insn + insn_size] & FLAG_SCANNED) ++ error ("Overlapping instructions in %s", name); ++ flags[insn + insn_size] |= FLAG_SCANNED; ++ insn_size++; ++ len--; ++ } ++ return insn_size; ++} ++ ++static void ++trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn, ++ int len) ++{ ++ uint8_t *ptr; ++ uint8_t op; ++ int modrm; ++ int is_prefix; ++ int op_size; ++ int addr_size; ++ int insn_size; ++ int is_ret; ++ int is_condjmp; ++ int is_jmp; ++ int is_exit; ++ int is_pcrel; ++ int immed; ++ int seen_rexw; ++ int32_t disp; ++ ++ ptr = start_p + insn; ++ /* nonzero if this insn has a ModR/M byte. */ ++ modrm = 1; ++ /* The size of the immediate value in this instruction. */ ++ immed = 0; ++ /* The operand size. */ ++ op_size = 4; ++ /* The address size */ ++ addr_size = 4; ++ /* The total length of this instruction. */ ++ insn_size = 0; ++ is_prefix = 1; ++ is_ret = 0; ++ is_condjmp = 0; ++ is_jmp = 0; ++ is_exit = 0; ++ seen_rexw = 0; ++ is_pcrel = 0; ++ ++ while (is_prefix) { ++ op = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ is_prefix = 0; ++ switch (op >> 4) { ++ case 0: ++ case 1: ++ case 2: ++ case 3: ++ if (op == 0x0f) { ++ /* two-byte opcode. */ ++ op = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ switch (op >> 4) { ++ case 0: ++ if ((op & 0xf) > 3) ++ modrm = 0; ++ break; ++ case 1: /* vector move or prefetch */ ++ case 2: /* various moves and vector compares. */ ++ case 4: /* cmov */ ++ case 5: /* vector instructions */ ++ case 6: ++ case 13: ++ case 14: ++ case 15: ++ break; ++ case 7: /* mmx */ ++ if (op & 0x77) /* emms */ ++ modrm = 0; ++ break; ++ case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */ ++ modrm = 0; ++ break; ++ case 8: /* long conditional jump */ ++ is_condjmp = 1; ++ immed = op_size; ++ modrm = 0; ++ break; ++ case 9: /* setcc */ ++ break; ++ case 10: ++ switch (op & 0x7) { ++ case 0: /* push fs/gs */ ++ case 1: /* pop fs/gs */ ++ case 2: /* cpuid/rsm */ ++ modrm = 0; ++ break; ++ case 4: /* shld/shrd immediate */ ++ immed = 1; ++ break; ++ default: /* Normal instructions with a ModR/M byte. */ ++ break; ++ } ++ break; ++ case 11: ++ switch (op & 0xf) { ++ case 10: /* bt, bts, btr, btc */ ++ immed = 1; ++ break; ++ default: ++ /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr ++ undefined, and movsx */ ++ break; ++ } ++ break; ++ case 12: ++ if (op & 8) { ++ /* bswap */ ++ modrm = 0; ++ } else { ++ switch (op & 0x7) { ++ case 2: ++ case 4: ++ case 5: ++ case 6: ++ immed = 1; ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ } ++ } else if ((op & 0x07) <= 0x3) { ++ /* General arithmentic ax. */ ++ } else if ((op & 0x07) <= 0x5) { ++ /* General arithmetic ax, immediate. */ ++ if (op & 0x01) ++ immed = op_size; ++ else ++ immed = 1; ++ modrm = 0; ++ } else if ((op & 0x23) == 0x22) { ++ /* Segment prefix. */ ++ is_prefix = 1; ++ } else { ++ /* Segment register push/pop or DAA/AAA/DAS/AAS. */ ++ modrm = 0; ++ } ++ break; ++ ++#if defined(HOST_X86_64) ++ case 4: /* rex prefix. */ ++ is_prefix = 1; ++ /* The address/operand size is actually 64-bit, but the immediate ++ values in the instruction are still 32-bit. */ ++ op_size = 4; ++ addr_size = 4; ++ if (op & 8) ++ seen_rexw = 1; ++ break; ++#else ++ case 4: /* inc/dec register. */ ++#endif ++ case 5: /* push/pop general register. */ ++ modrm = 0; ++ break; ++ ++ case 6: ++ switch (op & 0x0f) { ++ case 0: /* pusha */ ++ case 1: /* popa */ ++ modrm = 0; ++ break; ++ case 2: /* bound */ ++ case 3: /* arpl */ ++ break; ++ case 4: /* FS */ ++ case 5: /* GS */ ++ is_prefix = 1; ++ break; ++ case 6: /* opcode size prefix. */ ++ op_size = 2; ++ is_prefix = 1; ++ break; ++ case 7: /* Address size prefix. */ ++ addr_size = 2; ++ is_prefix = 1; ++ break; ++ case 8: /* push immediate */ ++ immed = op_size; ++ modrm = 0; ++ break; ++ case 10: /* push 8-bit immediate */ ++ immed = 1; ++ modrm = 0; ++ break; ++ case 9: /* imul immediate */ ++ immed = op_size; ++ break; ++ case 11: /* imul 8-bit immediate */ ++ immed = 1; ++ break; ++ case 12: /* insb */ ++ case 13: /* insw */ ++ case 14: /* outsb */ ++ case 15: /* outsw */ ++ modrm = 0; ++ break; ++ } ++ break; ++ ++ case 7: /* Short conditional jump. */ ++ is_condjmp = 1; ++ immed = 1; ++ modrm = 0; ++ break; ++ ++ case 8: ++ if ((op & 0xf) <= 3) { ++ /* arithmetic immediate. */ ++ if ((op & 3) == 1) ++ immed = op_size; ++ else ++ immed = 1; ++ } ++ /* else test, xchg, mov, lea or pop general. */ ++ break; ++ ++ case 9: ++ /* Various single-byte opcodes with no modrm byte. */ ++ modrm = 0; ++ if (op == 10) { ++ /* Call */ ++ immed = 4; ++ } ++ break; ++ ++ case 10: ++ switch ((op & 0xe) >> 1) { ++ case 0: /* mov absoliute immediate. */ ++ case 1: ++ if (seen_rexw) ++ immed = 8; ++ else ++ immed = addr_size; ++ break; ++ case 4: /* test immediate. */ ++ if (op & 1) ++ immed = op_size; ++ else ++ immed = 1; ++ break; ++ default: /* Various string ops. */ ++ break; ++ } ++ modrm = 0; ++ break; ++ ++ case 11: /* move immediate to register */ ++ if (op & 8) { ++ if (seen_rexw) ++ immed = 8; ++ else ++ immed = op_size; ++ } else { ++ immed = 1; ++ } ++ modrm = 0; ++ break; ++ ++ case 12: ++ switch (op & 0xf) { ++ case 0: /* shift immediate */ ++ case 1: ++ immed = 1; ++ break; ++ case 2: /* ret immediate */ ++ immed = 2; ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ case 3: /* ret */ ++ modrm = 0; ++ is_ret = 1; ++ case 4: /* les */ ++ case 5: /* lds */ ++ break; ++ case 6: /* mov immediate byte */ ++ immed = 1; ++ break; ++ case 7: /* mov immediate */ ++ immed = op_size; ++ break; ++ case 8: /* enter */ ++ /* TODO: Is this right? */ ++ immed = 3; ++ modrm = 0; ++ break; ++ case 10: /* retf immediate */ ++ immed = 2; ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ case 13: /* int */ ++ immed = 1; ++ modrm = 0; ++ break; ++ case 11: /* retf */ ++ case 15: /* iret */ ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ default: /* leave, int3 or into */ ++ modrm = 0; ++ break; ++ } ++ break; ++ ++ case 13: ++ if ((op & 0xf) >= 8) { ++ /* Coprocessor escape. For our purposes this is just a normal ++ instruction with a ModR/M byte. */ ++ } else if ((op & 0xf) >= 4) { ++ /* AAM, AAD or XLAT */ ++ modrm = 0; ++ } ++ /* else shift instruction */ ++ break; ++ ++ case 14: ++ switch ((op & 0xc) >> 2) { ++ case 0: /* loop or jcxz */ ++ is_condjmp = 1; ++ immed = 1; ++ break; ++ case 1: /* in/out immed */ ++ immed = 1; ++ break; ++ case 2: /* call or jmp */ ++ switch (op & 3) { ++ case 0: /* call */ ++ immed = op_size; ++ break; ++ case 1: /* long jump */ ++ immed = 4; ++ is_jmp = 1; ++ break; ++ case 2: /* far jmp */ ++ bad_opcode(name, op); ++ break; ++ case 3: /* short jmp */ ++ immed = 1; ++ is_jmp = 1; ++ break; ++ } ++ break; ++ case 3: /* in/out register */ ++ break; ++ } ++ modrm = 0; ++ break; ++ ++ case 15: ++ switch ((op & 0xe) >> 1) { ++ case 0: ++ case 1: ++ is_prefix = 1; ++ break; ++ case 2: ++ case 4: ++ case 5: ++ case 6: ++ modrm = 0; ++ /* Some privileged insns are used as markers. */ ++ switch (op) { ++ case 0xf4: /* hlt: Exit translation block. */ ++ is_exit = 1; ++ break; ++ case 0xfa: /* cli: Jump to label. */ ++ is_exit = 1; ++ immed = 4; ++ break; ++ case 0xfb: /* sti: TB patch jump. */ ++ /* Mark the insn for patching, but continue sscanning. */ ++ flags[insn] |= FLAG_EXIT; ++ immed = 4; ++ break; ++ } ++ break; ++ case 3: /* unary grp3 */ ++ if ((ptr[insn_size] & 0x38) == 0) { ++ if (op == 0xf7) ++ immed = op_size; ++ else ++ immed = 1; /* test immediate */ ++ } ++ break; ++ case 7: /* inc/dec grp4/5 */ ++ /* TODO: This includes indirect jumps. We should fail if we ++ encounter one of these. */ ++ break; ++ } ++ break; ++ } ++ } ++ ++ if (modrm) { ++ if (addr_size != 4) ++ error("16-bit addressing mode used in %s", name); ++ ++ disp = 0; ++ modrm = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ modrm &= 0xc7; ++ switch ((modrm & 0xc0) >> 6) { ++ case 0: ++ if (modrm == 5) ++ disp = 4; ++ break; ++ case 1: ++ disp = 1; ++ break; ++ case 2: ++ disp = 4; ++ break; ++ } ++ if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) { ++ /* SIB byte */ ++ if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) { ++ disp = 4; ++ is_pcrel = 1; ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, disp); ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, immed); ++ if (is_condjmp || is_jmp) { ++ if (immed == 1) { ++ disp = (int8_t)*(ptr + insn_size - 1); ++ } else { ++ disp = (((int32_t)*(ptr + insn_size - 1)) << 24) ++ | (((int32_t)*(ptr + insn_size - 2)) << 16) ++ | (((int32_t)*(ptr + insn_size - 3)) << 8) ++ | *(ptr + insn_size - 4); ++ } ++ disp += insn_size; ++ /* Jumps to external symbols point to the address of the offset ++ before relocation. */ ++ /* ??? These are probably a tailcall. We could fix them up by ++ replacing them with jmp to EOB + call, but it's easier to just ++ prevent the compiler generating them. */ ++ if (disp == 1) ++ error("Unconditional jump (sibcall?) in %s", name); ++ disp += insn; ++ if (disp < 0 || disp > len) ++ error("Jump outside instruction in %s", name); ++ ++ if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED) ++ error("Overlapping instructions in %s", name); ++ ++ flags[disp] |= (FLAG_INSN | FLAG_TARGET); ++ is_pcrel = 1; ++ } ++ if (is_pcrel) { ++ /* Mark the following insn as a jump target. This will stop ++ this instruction being moved. */ ++ flags[insn + insn_size] |= FLAG_TARGET; ++ } ++ if (is_ret) ++ flags[insn] |= FLAG_RET; ++ ++ if (is_exit) ++ flags[insn] |= FLAG_EXIT; ++ ++ if (!(is_jmp || is_ret || is_exit)) ++ flags[insn + insn_size] |= FLAG_INSN; ++} ++ ++/* Scan a function body. Returns the position of the return sequence. ++ Sets *patch_bytes to the number of bytes that need to be copied from that ++ location. If no patching is required (ie. the return is the last insn) ++ *patch_bytes will be set to -1. *plen is the number of code bytes to copy. ++ */ ++static int trace_i386_op(const char * name, uint8_t *start_p, int *plen, ++ int *patch_bytes, int *exit_addrs) ++{ ++ char *flags; ++ int more; ++ int insn; ++ int retpos; ++ int bytes; ++ int num_exits; ++ int len; ++ int last_insn; ++ ++ len = *plen; ++ flags = malloc(len + 1); ++ memset(flags, 0, len + 1); ++ flags[0] |= FLAG_INSN; ++ more = 1; ++ while (more) { ++ more = 0; ++ for (insn = 0; insn < len; insn++) { ++ if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) { ++ trace_i386_insn(name, start_p, flags, insn, len); ++ more = 1; ++ } ++ } ++ } ++ ++ /* Strip any unused code at the end of the function. */ ++ while (len > 0 && flags[len - 1] == 0) ++ len--; ++ ++ retpos = -1; ++ num_exits = 0; ++ last_insn = 0; ++ for (insn = 0; insn < len; insn++) { ++ if (flags[insn] & FLAG_RET) { ++ /* ??? In theory it should be possible to handle multiple return ++ points. In practice it's not worth the effort. */ ++ if (retpos != -1) ++ error("Multiple return instructions in %s", name); ++ retpos = insn; ++ } ++ if (flags[insn] & FLAG_EXIT) { ++ if (num_exits == MAX_EXITS) ++ error("Too many block exits in %s", name); ++ exit_addrs[num_exits] = insn; ++ num_exits++; ++ } ++ if (flags[insn] & FLAG_INSN) ++ last_insn = insn; ++ } ++ ++ exit_addrs[num_exits] = -1; ++ if (retpos == -1) { ++ if (num_exits == 0) { ++ error ("No return instruction found in %s", name); ++ } else { ++ retpos = len; ++ last_insn = len; ++ } ++ } ++ ++ /* If the return instruction is the last instruction we can just ++ remove it. */ ++ if (retpos == last_insn) ++ *patch_bytes = -1; ++ else ++ *patch_bytes = 0; ++ ++ /* Back up over any nop instructions. */ ++ while (retpos > 0 ++ && (flags[retpos] & FLAG_TARGET) == 0 ++ && (flags[retpos - 1] & FLAG_INSN) != 0 ++ && start_p[retpos - 1] == 0x90) { ++ retpos--; ++ } ++ ++ if (*patch_bytes == -1) { ++ *plen = retpos; ++ free (flags); ++ return retpos; ++ } ++ *plen = len; ++ ++ /* The ret is in the middle of the function. Find four more bytes that ++ so the ret can be replaced by a jmp. */ ++ /* ??? Use a short jump where possible. */ ++ bytes = 4; ++ insn = retpos + 1; ++ /* We can clobber everything up to the next jump target. */ ++ while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) { ++ insn++; ++ bytes--; ++ } ++ if (bytes > 0) { ++ /* ???: Strip out nop blocks. */ ++ /* We can't do the replacement without clobbering anything important. ++ Copy preceeding instructions(s) to give us some space. */ ++ while (retpos > 0) { ++ /* If this byte is the target of a jmp we can't move it. */ ++ if (flags[retpos] & FLAG_TARGET) ++ break; ++ ++ (*patch_bytes)++; ++ bytes--; ++ retpos--; ++ ++ /* Break out of the loop if we have enough space and this is either ++ the first byte of an instruction or a pad byte. */ ++ if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED ++ && bytes <= 0) { ++ break; ++ } ++ } ++ } ++ ++ if (bytes > 0) ++ error("Unable to replace ret with jmp in %s\n", name); ++ ++ free(flags); ++ return retpos; ++} ++ ++#endif ++ + #define MAX_ARGS 3 + + /* generate op code */ +@@ -1356,6 +1996,11 @@ void gen_code(const char *name, host_ulo + uint8_t args_present[MAX_ARGS]; + const char *sym_name, *p; + EXE_RELOC *rel; ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ int patch_bytes; ++ int retpos; ++ int exit_addrs[MAX_EXITS]; ++#endif + + /* Compute exact size excluding prologue and epilogue instructions. + * Increment start_offset to skip epilogue instructions, then compute +@@ -1366,33 +2011,12 @@ void gen_code(const char *name, host_ulo + p_end = p_start + size; + start_offset = offset; + #if defined(HOST_I386) || defined(HOST_X86_64) +-#ifdef CONFIG_FORMAT_COFF +- { +- uint8_t *p; +- p = p_end - 1; +- if (p == p_start) +- error("empty code for %s", name); +- while (*p != 0xc3) { +- p--; +- if (p <= p_start) +- error("ret or jmp expected at the end of %s", name); +- } +- copy_size = p - p_start; +- } +-#else + { + int len; + len = p_end - p_start; +- if (len == 0) +- error("empty code for %s", name); +- if (p_end[-1] == 0xc3) { +- len--; +- } else { +- error("ret or jmp expected at the end of %s", name); +- } ++ retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs); + copy_size = len; + } +-#endif + #elif defined(HOST_PPC) + { + uint8_t *p; +@@ -1559,6 +2183,13 @@ void gen_code(const char *name, host_ulo + } + + if (gen_switch == 2) { ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ if (patch_bytes != -1) ++ copy_size += patch_bytes; ++#ifdef DEBUG_OP ++ copy_size += 2; ++#endif ++#endif + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); + } else if (gen_switch == 1) { + +@@ -1761,7 +2392,43 @@ void gen_code(const char *name, host_ulo + #error unsupport object format + #endif + } ++ } ++ /* Replace the marker instructions with the actual opcodes. */ ++ for (i = 0; exit_addrs[i] != -1; i++) { ++ int op; ++ switch (p_start[exit_addrs[i]]) ++ { ++ case 0xf4: op = 0xc3; break; /* hlt -> ret */ ++ case 0xfa: op = 0xe9; break; /* cli -> jmp */ ++ case 0xfb: op = 0xe9; break; /* sti -> jmp */ ++ default: error("Internal error"); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ exit_addrs[i], op); + } ++ /* Fix up the return instruction. */ ++ if (patch_bytes != -1) { ++ if (patch_bytes) { ++ fprintf(outfile, " memcpy(gen_code_ptr + %d," ++ "gen_code_ptr + %d, %d);\n", ++ copy_size, retpos, patch_bytes); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", ++ retpos); ++ fprintf(outfile, ++ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ retpos + 1, copy_size - (retpos + 5)); ++ ++ copy_size += patch_bytes; ++ } ++#ifdef DEBUG_OP ++ fprintf(outfile, ++ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", ++ copy_size); ++ copy_size += 2; ++#endif + } + #elif defined(HOST_X86_64) + { +@@ -1793,6 +2460,42 @@ void gen_code(const char *name, host_ulo + } + } + } ++ /* Replace the marker instructions with the actual opcodes. */ ++ for (i = 0; exit_addrs[i] != -1; i++) { ++ int op; ++ switch (p_start[exit_addrs[i]]) ++ { ++ case 0xf4: op = 0xc3; break; /* hlt -> ret */ ++ case 0xfa: op = 0xe9; break; /* cli -> jmp */ ++ case 0xfb: op = 0xe9; break; /* sti -> jmp */ ++ default: error("Internal error"); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ exit_addrs[i], op); ++ } ++ /* Fix up the return instruction. */ ++ if (patch_bytes != -1) { ++ if (patch_bytes) { ++ fprintf(outfile, " memcpy(gen_code_ptr + %d," ++ "gen_code_ptr + %d, %d);\n", ++ copy_size, retpos, patch_bytes); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", ++ retpos); ++ fprintf(outfile, ++ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ retpos + 1, copy_size - (retpos + 5)); ++ ++ copy_size += patch_bytes; ++ } ++#ifdef DEBUG_OP ++ fprintf(outfile, ++ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", ++ copy_size); ++ copy_size += 2; ++#endif + } + #elif defined(HOST_PPC) + { +--- qemu-0.7.0/exec-all.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/exec-all.h 2005-06-02 21:41:51.000000000 +0200 +@@ -335,14 +335,15 @@ do {\ + + #elif defined(__i386__) && defined(USE_DIRECT_JUMP) + +-/* we patch the jump instruction directly */ ++/* we patch the jump instruction directly. Use sti in place of the actual ++ jmp instruction so that dyngen can patch in the correct result. */ + #define GOTO_TB(opname, tbparam, n)\ + do {\ + asm volatile (".section .data\n"\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ + ".long 1f\n"\ + ASM_PREVIOUS_SECTION \ +- "jmp " ASM_NAME(__op_jmp) #n "\n"\ ++ "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\ + "1:\n");\ + } while (0) + diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-i386-FORCE_RET.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-i386-FORCE_RET.patch.svn-base new file mode 100644 index 0000000..820399d --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-i386-FORCE_RET.patch.svn-base @@ -0,0 +1,26 @@ +2007-02-01 Mike Kronenberg + + * Fix for QEMU 0.9.0. + +2006-06-12 Gwenole Beauchesne + + * Try to enforce one exit point per synthetic opcode (gcc4). + +--- qemu-0.8.0/target-i386/op.c.i386-FORCE_RET 2005-12-19 23:51:53.000000000 +0100 ++++ qemu-0.8.0/target-i386/op.c 2006-02-12 17:51:40.000000000 +0100 +@@ -1032,6 +1032,7 @@ void OPPROTO op_aaa(void) + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; ++ FORCE_RET(); + } + + void OPPROTO op_aas(void) +@@ -1056,6 +1057,7 @@ void OPPROTO op_aas(void) + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; ++ FORCE_RET(); + } + + /* segment handling */ diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-osx-intel-port.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-osx-intel-port.patch.svn-base new file mode 100644 index 0000000..348b823 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-osx-intel-port.patch.svn-base @@ -0,0 +1,329 @@ +2007-02-01 Mike Kronenberg + + * Fix for QEMU 0.9.0. + +2006-02-12 Gwenole Beauchesne + + * Port to MacOS X for Intel. + +TODO: + - try test-i386 + - use 80-bit long double? + +--- qemu-0.8.0/target-i386/exec.h.osx-intel-port 2005-12-19 23:51:53.000000000 +0100 ++++ qemu-0.8.0/target-i386/exec.h 2006-02-13 07:20:25.000000000 +0100 +@@ -457,8 +457,6 @@ static inline void helper_fstt(CPU86_LDo + + #define FPUC_EM 0x3f + +-extern const CPU86_LDouble f15rk[7]; +- + void helper_fldt_ST0_A0(void); + void helper_fstt_ST0_A0(void); + void fpu_raise_exception(void); +@@ -492,10 +490,6 @@ float approx_rsqrt(float a); + float approx_rcp(float a); + void update_fp_status(void); + +-extern const uint8_t parity_table[256]; +-extern const uint8_t rclw_table[32]; +-extern const uint8_t rclb_table[32]; +- + static inline uint32_t compute_eflags(void) + { + return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); +--- qemu-0.8.0/target-i386/op.c.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/target-i386/op.c 2006-02-13 07:20:25.000000000 +0100 +@@ -21,6 +21,19 @@ + #define ASM_SOFTMMU + #include "exec.h" + ++#if defined(__APPLE__) ++/* XXX avoid indirect symbols, correct address patched at code generation time. */ ++static const uint8_t parity_table[256]; ++static const uint8_t rclw_table[32]; ++static const uint8_t rclb_table[32]; ++static const CPU86_LDouble f15rk[7]; ++#else ++extern const uint8_t parity_table[256]; ++extern const uint8_t rclw_table[32]; ++extern const uint8_t rclb_table[32]; ++extern const CPU86_LDouble f15rk[7]; ++#endif ++ + /* n must be a constant to be efficient */ + static inline target_long lshift(target_long x, int n) + { +--- qemu-0.8.0/Makefile.target.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/Makefile.target 2006-02-13 01:25:58.000000000 +0100 +@@ -18,6 +18,9 @@ CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) + endif + BASE_CFLAGS= + BASE_LDFLAGS= ++ifeq ($(CONFIG_DARWIN),yes) ++CFLAGS+=-mdynamic-no-pic ++endif + #CFLAGS+=-Werror + LDFLAGS=-g + LIBS= +--- qemu-0.8.0/dyngen.c.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/dyngen.c 2006-02-13 01:25:58.000000000 +0100 +@@ -183,6 +183,20 @@ typedef struct coff_rel { + #include + #include + ++#ifdef HOST_PPC ++ ++#define MACH_CPU_TYPE CPU_TYPE_POWERPC ++#define mach_check_cputype(x) ((x) == CPU_TYPE_POWERPC) ++ ++#elif defined(HOST_I386) ++ ++#define MACH_CPU_TYPE CPU_TYPE_I386 ++#define mach_check_cputype(x) ((x) == CPU_TYPE_I386) ++ ++#else ++#error unsupported CPU - please update the code ++#endif ++ + # define check_mach_header(x) (x.magic == MH_MAGIC) + typedef int32_t host_long; + typedef uint32_t host_ulong; +@@ -981,22 +995,23 @@ static const char * find_reloc_name_in_s + { + unsigned int tocindex, symindex, size; + const char *name = 0; ++ int section_type; + + /* Sanity check */ + if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) ) + return (char*)0; +- +- if( sec_hdr->flags & S_SYMBOL_STUBS ){ ++ ++ section_type = sec_hdr->flags & SECTION_TYPE; ++ if( section_type == S_SYMBOL_STUBS ){ + size = sec_hdr->reserved2; + if(size == 0) + error("size = 0"); +- + } +- else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS || +- sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS) ++ else if( section_type == S_LAZY_SYMBOL_POINTERS || ++ section_type == S_NON_LAZY_SYMBOL_POINTERS) + size = sizeof(unsigned long); + else +- return 0; ++ return NULL; + + /* Compute our index in toc */ + tocindex = (address - sec_hdr->addr)/size; +@@ -1030,8 +1045,27 @@ static const char * get_reloc_name(EXE_R + /* init the slide value */ + *sslide = 0; + +- if(R_SCATTERED & rel->r_address) +- return (char *)find_reloc_name_given_its_address(sca_rel->r_value); ++ if (R_SCATTERED & rel->r_address) { ++ char *name = (char *)find_reloc_name_given_its_address(sca_rel->r_value); ++ ++ /* search it in the full symbol list, if not found */ ++ if (!name) { ++ int i; ++ for (i = 0; i < nb_syms; i++) { ++ EXE_SYM *sym = &symtab[i]; ++ if (sym->st_value == sca_rel->r_value) { ++ name = get_sym_name(sym); ++ switch (sca_rel->r_type) { ++ case GENERIC_RELOC_VANILLA: ++ *sslide = *(uint32_t *)(text + sca_rel->r_address) - sca_rel->r_value; ++ break; ++ } ++ break; ++ } ++ } ++ } ++ return name; ++ } + + if(rel->r_extern) + { +@@ -1063,14 +1097,21 @@ static const char * get_reloc_name(EXE_R + sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc ); + if (sectoffset & 0x02000000) sectoffset |= 0xfc000000; + break; ++ case GENERIC_RELOC_VANILLA: ++ sectoffset = *(uint32_t *)(text + rel->r_address); ++ break; + default: +- error("switch(rel->type) not found"); ++ error("switch(rel->type=%d) not found", rel->r_type); + } + +- if(rel->r_pcrel) ++ if(rel->r_pcrel) { + sectoffset += rel->r_address; +- +- if (rel->r_type == PPC_RELOC_BR24) ++#ifdef HOST_I386 ++ sectoffset += (1 << rel->r_length); ++#endif ++ } ++ ++ if (rel->r_type == PPC_RELOC_BR24 || rel->r_pcrel) + name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, §ion_hdr[sectnum-1]); + + /* search it in the full symbol list, if not found */ +@@ -1122,7 +1163,7 @@ int load_object(const char *filename) + error("bad Mach header"); + } + +- if (mach_hdr.cputype != CPU_TYPE_POWERPC) ++ if (!mach_check_cputype(mach_hdr.cputype)) + error("Unsupported CPU"); + + if (mach_hdr.filetype != MH_OBJECT) +@@ -2413,6 +2454,82 @@ void gen_code(const char *name, host_ulo + /* patch relocations */ + #if defined(HOST_I386) + { ++#ifdef CONFIG_FORMAT_MACH ++ struct scattered_relocation_info *scarel; ++ struct relocation_info * rel; ++ char final_sym_name[256]; ++ const char *sym_name; ++ const char *p; ++ int slide, sslide; ++ int i; ++ ++ for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { ++ unsigned int offset, length, value = 0; ++ unsigned int type, pcrel, isym = 0; ++ unsigned int usesym = 0; ++ ++ if (R_SCATTERED & rel->r_address) { ++ scarel = (struct scattered_relocation_info*)rel; ++ offset = (unsigned int)scarel->r_address; ++ length = scarel->r_length; ++ pcrel = scarel->r_pcrel; ++ type = scarel->r_type; ++ value = scarel->r_value; ++ } ++ else { ++ value = isym = rel->r_symbolnum; ++ usesym = (rel->r_extern); ++ offset = rel->r_address; ++ length = rel->r_length; ++ pcrel = rel->r_pcrel; ++ type = rel->r_type; ++ } ++ ++ slide = offset - start_offset; ++ ++ if (!(offset >= start_offset && offset < start_offset + size)) ++ continue; /* not in our range */ ++ ++ sym_name = get_reloc_name(rel, &sslide); ++ ++ if (usesym && symtab[isym].n_type & N_STAB) ++ continue; /* don't handle STAB (debug sym) */ ++ ++ if (sym_name && strstart(sym_name, "__op_jmp", &p)) { ++ int n; ++ n = strtol(p, NULL, 10); ++ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, slide); ++ continue; /* Nothing more to do */ ++ } ++ ++ if (!sym_name) { ++ fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n", ++ name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type); ++ continue; /* dunno how to handle without final_sym_name */ ++ } ++ ++ get_reloc_expr(final_sym_name, sizeof(final_sym_name), ++ sym_name); ++ ++ if (length != 2) ++ error("unsupported %d-bit relocation", 8 * (1 << length)); ++ ++ switch (type) { ++ case GENERIC_RELOC_VANILLA: ++ if (pcrel || strstart(sym_name,"__op_gen_label",&p)) { ++ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) - 4;\n", ++ slide, final_sym_name, slide); ++ } ++ else { ++ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (%s + %d);\n", ++ slide, final_sym_name, sslide); ++ } ++ break; ++ default: ++ error("unsupported i386 relocation (%d)", type); ++ } ++ } ++#else + char name[256]; + int type; + int addend; +@@ -2482,6 +2599,7 @@ void gen_code(const char *name, host_ulo + #endif + } + } ++#endif + /* Replace the marker instructions with the actual opcodes. */ + for (i = 0; exit_addrs[i] != -1; i++) { + int op; +--- qemu-0.8.0/dyngen-exec.h.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/dyngen-exec.h 2006-02-13 01:25:58.000000000 +0100 +@@ -215,9 +215,16 @@ extern int __op_jmp0, __op_jmp1, __op_jm + #define EXIT_TB() asm volatile ("hlt") + /* Dyngen will replace cli with 0x9e (jmp). + We generate the offset manually. */ ++#if defined(__APPLE__) ++/* XXX Different relocations are generated for MacOS X for Intel ++ (please as from cctools). */ ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n) ++#else + #define GOTO_LABEL_PARAM(n) \ + asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif ++#endif + #ifdef __x86_64__ + /* The same as i386. */ + #define EXIT_TB() asm volatile ("hlt") +--- qemu-0.8.0/exec-all.h.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/exec-all.h 2006-02-13 01:25:58.000000000 +0100 +@@ -321,15 +321,29 @@ do {\ + + /* we patch the jump instruction directly. Use sti in place of the actual + jmp instruction so that dyngen can patch in the correct result. */ ++#if defined(__APPLE__) ++/* XXX Different relocations are generated for MacOS X for Intel ++ (please as from cctools). */ + #define GOTO_TB(opname, tbparam, n)\ + do {\ +- asm volatile (".section .data\n"\ ++ asm volatile (ASM_DATA_SECTION\ ++ ASM_OP_LABEL_NAME(n, opname) ":\n"\ ++ ".long 1f\n"\ ++ ASM_PREVIOUS_SECTION \ ++ "sti;.long " ASM_NAME(__op_jmp) #n "\n"\ ++ "1:\n");\ ++} while (0) ++#else ++#define GOTO_TB(opname, tbparam, n)\ ++do {\ ++ asm volatile (ASM_DATA_SECTION\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ + ".long 1f\n"\ + ASM_PREVIOUS_SECTION \ + "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\ + "1:\n");\ + } while (0) ++#endif + + #else + diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-qcow2.diff.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-qcow2.diff.svn-base new file mode 100644 index 0000000..89a499c --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-qcow2.diff.svn-base @@ -0,0 +1,26 @@ +--- block-qcow2.c 2006/08/07 02:38:06 1.4 ++++ block-qcow2.c 2007/04/02 12:48:47 1.6 +@@ -1886,6 +1886,8 @@ + int64_t table_offset; + uint64_t data64; + uint32_t data32; ++ int old_table_size; ++ int64_t old_table_offset; + + if (min_size <= s->refcount_table_size) + return 0; +@@ -1931,10 +1933,14 @@ + &data32, sizeof(data32)) != sizeof(data32)) + goto fail; + qemu_free(s->refcount_table); ++ old_table_offset = s->refcount_table_offset; ++ old_table_size = s->refcount_table_size; + s->refcount_table = new_table; + s->refcount_table_size = new_table_size; ++ s->refcount_table_offset = table_offset; + + update_refcount(bs, table_offset, new_table_size2, 1); ++ free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); + return 0; + fail: + free_clusters(bs, table_offset, new_table_size2); diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-clobber.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-clobber.patch.svn-base new file mode 100644 index 0000000..dc6c792 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-clobber.patch.svn-base @@ -0,0 +1,10 @@ +--- qemu-0.9.0/cpu-exec.c 2007-07-22 18:05:41.000000000 +0200 ++++ qemu/cpu-exec.c 2007-07-22 18:04:24.000000000 +0200 +@@ -645,6 +645,7 @@ + : /* no outputs */ + : "r" (gen_func) + : "i0", "i1", "i2", "i3", "i4", "i5", ++ "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5", + "l6", "l7"); + #elif defined(__arm__) diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-compile-flags.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-compile-flags.patch.svn-base new file mode 100644 index 0000000..8d09aac --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-compile-flags.patch.svn-base @@ -0,0 +1,23 @@ +diff -ur qemu/Makefile.target qemu-ecd/Makefile.target +--- qemu/Makefile.target 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/Makefile.target 2007-07-22 19:33:00.000000000 +0200 +@@ -122,14 +122,14 @@ + + ifeq ($(ARCH),sparc) + ifeq ($(CONFIG_SOLARIS),yes) +-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 ++BASE_CFLAGS+=-mcpu=ultrasparc -m32 -U__sparc_v9__ + BASE_LDFLAGS+=-m32 +-OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 ++OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -Wa,-Av9a + else +-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 ++BASE_CFLAGS+=-mcpu=ultrasparc -m32 -U__sparc_v9__ + BASE_LDFLAGS+=-m32 +-OP_CFLAGS+=-fno-delayed-branch -ffixed-i0 +-HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat ++OP_CFLAGS+=-fno-delayed-branch -Wa,-Av9a ++HELPER_CFLAGS=$(CFLAGS) + # -static is used to avoid g1/g3 usage by the dynamic linker + BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static + endif diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-load-store-le.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-load-store-le.patch.svn-base new file mode 100644 index 0000000..7ec7453 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-load-store-le.patch.svn-base @@ -0,0 +1,67 @@ +diff -ur qemu/cpu-all.h qemu-0.9.0/cpu-all.h +--- qemu/cpu-all.h 2007-07-21 11:53:24.000000000 +0200 ++++ qemu-0.9.0/cpu-all.h 2007-07-04 09:48:06.000000000 +0200 +@@ -24,6 +24,12 @@ + #define WORDS_ALIGNED + #endif + ++#if defined(__sparc__) ++#ifndef ASI_PL ++#define ASI_PL 0x88 ++#endif ++#endif ++ + /* some important defines: + * + * WORDS_ALIGNED : if defined, the host cpu can only make word aligned +@@ -197,6 +203,10 @@ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; ++#elif defined(__sparc__) ++ uint16_t val; ++ __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return p[0] | (p[1] << 8); +@@ -209,6 +219,10 @@ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; ++#elif defined(__sparc__) ++ int16_t val; ++ __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +@@ -221,6 +235,10 @@ + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; ++#elif defined(__sparc__) ++ uint32_t val; ++ __asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +@@ -240,6 +258,8 @@ + { + #ifdef __powerpc__ + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); ++#elif defined(__sparc__) ++ __asm__ __volatile__ ("stha %0, [%1] %2" : : "r" (v), "r" (ptr), "i" (ASI_PL)); + #else + uint8_t *p = ptr; + p[0] = v; +@@ -251,6 +271,8 @@ + { + #ifdef __powerpc__ + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); ++#elif defined(__sparc__) ++ __asm__ __volatile__ ("stwa %0, [%1] %2" : : "r" (v), "r" (ptr), "i" (ASI_PL)); + #else + uint8_t *p = ptr; + p[0] = v; diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-register.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-register.patch.svn-base new file mode 100644 index 0000000..59a7e1f --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-sparc-register.patch.svn-base @@ -0,0 +1,173 @@ +diff -ur qemu/cpu-exec.c qemu-ecd/cpu-exec.c +--- qemu/cpu-exec.c 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/cpu-exec.c 2007-07-22 19:26:22.000000000 +0200 +@@ -233,10 +233,6 @@ + uint32_t *saved_regwptr; + #endif + #endif +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- int saved_i7; +- target_ulong tmp_T0; +-#endif + int ret, interrupt_request; + void (*gen_func)(void); + TranslationBlock *tb; +@@ -300,10 +296,6 @@ + #define SAVE_HOST_REGS 1 + #include "hostregs_helper.h" + env = env1; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- /* we also save i7 because longjmp may not restore it */ +- asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); +-#endif + + #if defined(TARGET_I386) + env_to_regs(); +@@ -403,10 +395,6 @@ + + T0 = 0; /* force lookup of first TB */ + for(;;) { +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- /* g1 can be modified by some libc? functions */ +- tmp_T0 = T0; +-#endif + interrupt_request = env->interrupt_request; + if (__builtin_expect(interrupt_request, 0)) { + #if defined(TARGET_I386) +@@ -414,11 +402,7 @@ + !(env->hflags & HF_SMM_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { +@@ -431,11 +415,7 @@ + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + #elif defined(TARGET_PPC) + #if 0 +@@ -450,22 +430,14 @@ + env->error_code = 0; + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { + /* Raise it */ + env->exception_index = EXCP_DECR; + env->error_code = 0; + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + } + #elif defined(TARGET_MIPS) +@@ -479,11 +451,7 @@ + env->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + do_interrupt(env); +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + #elif defined(TARGET_SPARC) + if ((interrupt_request & CPU_INTERRUPT_HARD) && +@@ -497,11 +465,7 @@ + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + do_interrupt(env->interrupt_index); + env->interrupt_index = 0; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + } else if (interrupt_request & CPU_INTERRUPT_TIMER) { + //do_interrupt(0, 0, 0, 0, 0); +@@ -532,11 +496,7 @@ + env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + /* ensure that no TB jump will be modified as + the program flow was changed */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + if (interrupt_request & CPU_INTERRUPT_EXIT) { + env->interrupt_request &= ~CPU_INTERRUPT_EXIT; +@@ -606,9 +566,6 @@ + lookup_symbol(tb->pc)); + } + #endif +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- T0 = tmp_T0; +-#endif + /* see if we can patch the calling TB. When the TB + spans two pages, we cannot safely do a direct + jump. */ +@@ -800,9 +757,6 @@ + #endif + + /* restore global registers */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); +-#endif + #include "hostregs_helper.h" + + /* fail safe : never use cpu_single_env outside cpu_exec() */ +diff -ur qemu/dyngen-exec.h qemu-ecd/dyngen-exec.h +--- qemu/dyngen-exec.h 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/dyngen-exec.h 2007-07-22 19:26:22.000000000 +0200 +@@ -142,19 +142,6 @@ + #define AREG1 "g4" + #define AREG2 "g5" + #define AREG3 "g7" +-#else +-#define AREG0 "g6" +-#define AREG1 "g1" +-#define AREG2 "g2" +-#define AREG3 "g3" +-#define AREG4 "l0" +-#define AREG5 "l1" +-#define AREG6 "l2" +-#define AREG7 "l3" +-#define AREG8 "l4" +-#define AREG9 "l5" +-#define AREG10 "l6" +-#define AREG11 "l7" + #endif + #endif + #define USE_FP_CONVERT +diff -ur qemu/target-arm/exec.h qemu-ecd/target-arm/exec.h +--- qemu/target-arm/exec.h 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-ecd/target-arm/exec.h 2007-07-22 19:30:15.000000000 +0200 +@@ -17,6 +17,7 @@ + * 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 "dyngen-exec.h" + + #if defined(__sparc__) diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-dump-state.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-dump-state.patch.svn-base new file mode 100644 index 0000000..11febb0 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-dump-state.patch.svn-base @@ -0,0 +1,37 @@ +diff -ur qemu/target-arm/translate.c qemu-0.9.0/target-arm/translate.c +--- qemu/target-arm/translate.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/target-arm/translate.c 2007-07-10 09:15:56.000000000 +0200 +@@ -2536,7 +2536,9 @@ + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) + { ++ uint32_t psr; + int i; ++#ifndef X49GP + union { + uint32_t i; + float s; +@@ -2548,7 +2550,7 @@ + float64 f64; + double d; + } d0; +- uint32_t psr; ++#endif + + for(i=0;i<16;i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); +@@ -2567,6 +2567,7 @@ + psr & CPSR_T ? 'T' : 'A', + cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); + ++#ifndef X49GP + for (i = 0; i < 16; i++) { + d.d = env->vfp.regs[i]; + s0.i = d.l.lower; +@@ -2579,5 +2580,6 @@ + d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); ++#endif + } + diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-mmu.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-mmu.patch.svn-base new file mode 100644 index 0000000..0a54ae1 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-mmu.patch.svn-base @@ -0,0 +1,192 @@ +diff -ur qemu-0.9.0/target-arm/helper.c qemu/target-arm/helper.c +--- qemu-0.9.0/target-arm/helper.c 2007-07-30 16:48:18.000000000 +0200 ++++ qemu/target-arm/helper.c 2007-07-30 16:46:50.000000000 +0200 +@@ -278,87 +280,101 @@ + static int get_phys_addr(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) + { +- int code; +- uint32_t table; +- uint32_t desc; +- int type; +- int ap; +- int domain; +- uint32_t phys_addr; ++ int code; ++ uint32_t pgdp, ptep; ++ uint32_t pgd, pte = 0; ++ uint32_t index; ++ int ap = 0; ++ int domain = 0; ++ uint32_t phys_addr = 0; ++ ++ /* Fast Context Switch Extension. */ ++ if (address < 0x02000000) ++ address += env->cp15.c13_fcse; ++ ++ if ((env->cp15.c1_sys & 1) == 0) { ++ /* MMU disabled. */ ++ *phys_ptr = address; ++ *prot = PAGE_READ | PAGE_WRITE; ++ return 0; ++ } ++ ++ /* Pagetable walk. */ ++ ++ /* Lookup l1 descriptor. */ ++ pgdp = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); ++ ++ pgd = ldl_phys(pgdp); ++ ++ switch (pgd & 3) { ++ case 0: /* Section translation fault. */ ++ code = 5; ++ goto do_fault; ++ ++ case 1: /* Coarse page table. */ ++ index = (address >> 10) & 0x3fc; ++ ptep = (pgd & 0xfffffc00) | index; ++ ++ pte = ldl_phys(ptep); ++ break; ++ ++ case 2: /* Section. */ ++ phys_addr = (pgd & 0xfff00000) | (address & 0x000fffff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pgd >> 10) & 0x03; ++ code = 13; ++ ++ goto do_check; ++ ++ case 3: /* Fine page table. */ ++ index = (address >> 8) & 0xffc; ++ ptep = (pgd & 0xfffff000) | index; ++ ++ pte = ldl_phys(ptep); ++ break; ++ } ++ ++ code = 15; ++ switch (pte & 3) { ++ case 0: /* Page translation fault. */ ++ code = 7; ++ goto do_fault; ++ ++ case 1: /* Large page. */ ++ phys_addr = (pte & 0xffff0000) | (address & 0x0000ffff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> (4 + ((address >> 13) & 6))) & 3; ++ break; ++ ++ case 2: /* Small page. */ ++ phys_addr = (pte & 0xfffff000) | (address & 0x00000fff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> (4 + ((address >> 13) & 6))) & 3; ++ break; ++ ++ case 3: /* Tiny page. */ ++ phys_addr = (pte & 0xfffffc00) | (address & 0x000003ff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> 4) & 3; ++ break; ++ } ++ ++do_check: ++ *prot = check_ap(env, ap, domain, access_type, is_user); ++ if (!*prot) { ++ /* Access permission fault. */ ++ goto do_fault; ++ } + +- /* Fast Context Switch Extension. */ +- if (address < 0x02000000) +- address += env->cp15.c13_fcse; +- +- if ((env->cp15.c1_sys & 1) == 0) { +- /* MMU diusabled. */ +- *phys_ptr = address; +- *prot = PAGE_READ | PAGE_WRITE; +- } else { +- /* Pagetable walk. */ +- /* Lookup l1 descriptor. */ +- table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); +- desc = ldl_phys(table); +- type = (desc & 3); +- domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; +- if (type == 0) { +- /* Secton translation fault. */ +- code = 5; +- goto do_fault; +- } +- if (domain == 0 || domain == 2) { +- if (type == 2) +- code = 9; /* Section domain fault. */ +- else +- code = 11; /* Page domain fault. */ +- goto do_fault; +- } +- if (type == 2) { +- /* 1Mb section. */ +- phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); +- ap = (desc >> 10) & 3; +- code = 13; +- } else { +- /* Lookup l2 entry. */ +- table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); +- desc = ldl_phys(table); +- switch (desc & 3) { +- case 0: /* Page translation fault. */ +- code = 7; +- goto do_fault; +- case 1: /* 64k page. */ +- phys_addr = (desc & 0xffff0000) | (address & 0xffff); +- ap = (desc >> (4 + ((address >> 13) & 6))) & 3; +- break; +- case 2: /* 4k page. */ +- phys_addr = (desc & 0xfffff000) | (address & 0xfff); +- ap = (desc >> (4 + ((address >> 13) & 6))) & 3; +- break; +- case 3: /* 1k page. */ +- if (type == 1) { +- /* Page translation fault. */ +- code = 7; +- goto do_fault; +- } +- phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); +- ap = (desc >> 4) & 3; +- break; +- default: +- /* Never happens, but compiler isn't smart enough to tell. */ +- abort(); +- } +- code = 15; +- } +- *prot = check_ap(env, ap, domain, access_type, is_user); +- if (!*prot) { +- /* Access permission fault. */ +- goto do_fault; +- } + *phys_ptr = phys_addr; +- } +- return 0; ++ return 0; ++ + do_fault: +- return code | (domain << 4); ++ return code | (domain << 4); + } + + int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, +@@ -532,7 +548,7 @@ + return; + bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ +- cpu_abort(env, "Unimplemented cp15 register read\n"); ++ cpu_abort(env, "Unimplemented cp15 register write\n"); + } + + uint32_t helper_get_cp15(CPUState *env, uint32_t insn) diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-semihosting.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-semihosting.patch.svn-base new file mode 100644 index 0000000..f343239 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-arm-semihosting.patch.svn-base @@ -0,0 +1,50 @@ +diff -ur qemu/arm-semi.c qemu-0.9.0/arm-semi.c +--- qemu/arm-semi.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/arm-semi.c 2007-07-03 21:52:52.000000000 +0200 +@@ -196,7 +196,7 @@ + + #define ARG(n) tget32(args + (n) * 4) + #define SET_ARG(n, val) tput32(args + (n) * 4,val) +-uint32_t do_arm_semihosting(CPUState *env) ++int do_arm_semihosting(CPUState *env, uint32_t mask) + { + target_ulong args; + char * s; +diff -ur qemu/linux-user/arm/syscall.h qemu-0.9.0/linux-user/arm/syscall.h +--- qemu/linux-user/arm/syscall.h 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/linux-user/arm/syscall.h 2007-07-03 21:54:32.000000000 +0200 +@@ -39,4 +39,4 @@ + #define UNAME_MACHINE "armv5tel" + #endif + +-uint32_t do_arm_semihosting(CPUState *); ++int do_arm_semihosting(CPUState *, uint32_t); +diff -ur qemu/target-arm/helper.c qemu-0.9.0/target-arm/helper.c +--- qemu/target-arm/helper.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/target-arm/helper.c 2007-07-21 11:44:15.000000000 +0200 +@@ -5,6 +5,8 @@ + #include "cpu.h" + #include "exec-all.h" + ++extern int do_arm_semihosting(CPUARMState *env, uint32_t mask); ++ + void cpu_reset(CPUARMState *env) + { + #if defined (CONFIG_USER_ONLY) +@@ -184,14 +184,8 @@ + } else { + mask = ldl_code(env->regs[15] - 4) & 0xffffff; + } +- /* Only intercept calls from privileged modes, to provide some +- semblance of security. */ +- if (((mask == 0x123456 && !env->thumb) +- || (mask == 0xab && env->thumb)) +- && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { +- env->regs[0] = do_arm_semihosting(env); +- return; +- } ++ if (do_arm_semihosting(env, mask)) ++ return; + } + new_mode = ARM_CPU_MODE_SVC; + addr = 0x08; diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-block.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-block.patch.svn-base new file mode 100644 index 0000000..9f579b6 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-block.patch.svn-base @@ -0,0 +1,1302 @@ +diff -ur qemu-0.9.0/block-qcow.c qemu/block-qcow.c +--- qemu-0.9.0/block-qcow.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-qcow.c 2007-07-30 14:30:18.000000000 +0200 +@@ -69,10 +69,12 @@ + uint8_t *cluster_cache; + uint8_t *cluster_data; + uint64_t cluster_cache_offset; ++#ifndef X49GP + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ + uint32_t crypt_method_header; + AES_KEY aes_encrypt_key; + AES_KEY aes_decrypt_key; ++#endif + } BDRVQcowState; + + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); +@@ -115,9 +117,11 @@ + goto fail; + if (header.crypt_method > QCOW_CRYPT_AES) + goto fail; ++#ifndef X49GP + s->crypt_method_header = header.crypt_method; + if (s->crypt_method_header) + bs->encrypted = 1; ++#endif + s->cluster_bits = header.cluster_bits; + s->cluster_size = 1 << s->cluster_bits; + s->cluster_sectors = 1 << (s->cluster_bits - 9); +@@ -172,6 +176,8 @@ + return -1; + } + ++#ifndef X49GP ++ + static int qcow_set_key(BlockDriverState *bs, const char *key) + { + BDRVQcowState *s = bs->opaque; +@@ -239,6 +245,8 @@ + } + } + ++#endif /* !(X49GP) */ ++ + /* 'allocate' is: + * + * 0 to not allocate. +@@ -344,6 +352,7 @@ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + bdrv_truncate(s->hd, cluster_offset + s->cluster_size); ++#ifndef X49GP + /* if encrypted, we must initialize the cluster + content which won't be written */ + if (s->crypt_method && +@@ -363,6 +372,7 @@ + } + } + } ++#endif /* !(X49GP) */ + } else { + cluster_offset |= QCOW_OFLAG_COMPRESSED | + (uint64_t)compressed_size << (63 - s->cluster_bits); +@@ -442,7 +452,7 @@ + return 0; + } + +-#if 0 ++#ifdef X49GP + + static int qcow_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +@@ -474,10 +484,12 @@ + ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + if (ret != n * 512) + return -1; ++#ifndef X49GP + if (s->crypt_method) { + encrypt_sectors(s, sector_num, buf, buf, n, 0, + &s->aes_decrypt_key); + } ++#endif /* !(X49GP) */ + } + nb_sectors -= n; + sector_num += n; +@@ -485,7 +497,8 @@ + } + return 0; + } +-#endif ++ ++#endif /* X49GP */ + + static int qcow_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +@@ -504,12 +517,15 @@ + index_in_cluster + n); + if (!cluster_offset) + return -1; ++#ifndef X49GP + if (s->crypt_method) { + encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, + &s->aes_encrypt_key); + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, + s->cluster_data, n * 512); +- } else { ++ } else ++#endif /* !(X49GP) */ ++ { + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + } + if (ret != n * 512) +@@ -522,6 +538,8 @@ + return 0; + } + ++#ifndef X49GP ++ + typedef struct QCowAIOCB { + BlockDriverAIOCB common; + int64_t sector_num; +@@ -554,12 +572,14 @@ + /* nothing to do */ + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* nothing to do */ ++#ifndef X49GP + } else { + if (s->crypt_method) { + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, + &s->aes_decrypt_key); + } ++#endif + } + + acb->nb_sectors -= acb->n; +@@ -673,6 +693,7 @@ + ret = -EIO; + goto fail; + } ++#ifndef X49GP + if (s->crypt_method) { + if (!acb->cluster_data) { + acb->cluster_data = qemu_mallocz(s->cluster_size); +@@ -684,7 +705,9 @@ + encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, + acb->n, 1, &s->aes_encrypt_key); + src_buf = acb->cluster_data; +- } else { ++ } else ++#endif /* !(X49GP) */ ++ { + src_buf = acb->buf; + } + acb->hd_aiocb = bdrv_aio_write(s->hd, +@@ -725,6 +748,8 @@ + qemu_aio_release(acb); + } + ++#endif /* !(X49GP) */ ++ + static void qcow_close(BlockDriverState *bs) + { + BDRVQcowState *s = bs->opaque; +@@ -887,19 +912,30 @@ + sizeof(BDRVQcowState), + qcow_probe, + qcow_open, ++#ifdef X49GP ++ qcow_read, ++ qcow_write, ++#else + NULL, + NULL, ++#endif + qcow_close, + qcow_create, + qcow_flush, + qcow_is_allocated, ++#ifndef X49GP + qcow_set_key, ++#else ++ NULL, ++#endif + qcow_make_empty, + ++#ifndef X49GP + .bdrv_aio_read = qcow_aio_read, + .bdrv_aio_write = qcow_aio_write, + .bdrv_aio_cancel = qcow_aio_cancel, + .aiocb_size = sizeof(QCowAIOCB), ++#endif + .bdrv_write_compressed = qcow_write_compressed, + .bdrv_get_info = qcow_get_info, + }; +diff -ur qemu-0.9.0/block-raw.c qemu/block-raw.c +--- qemu-0.9.0/block-raw.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-raw.c 2007-07-30 14:30:18.000000000 +0200 +@@ -27,6 +27,10 @@ + #ifndef _WIN32 + #include + ++#ifdef X49GP ++#define QEMU_TOOL ++#endif ++ + #ifndef QEMU_TOOL + #include "exec-all.h" + #endif +@@ -157,6 +161,7 @@ + return ret; + } + ++#ifndef X49GP + /***********************************************************/ + /* Unix AIO using POSIX AIO */ + +@@ -379,6 +384,7 @@ + pacb = &acb->next; + } + } ++#endif /* !(X49GP) */ + + static void raw_close(BlockDriverState *bs) + { +@@ -479,11 +485,12 @@ + raw_close, + raw_create, + raw_flush, +- ++#ifndef X49GP + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), ++#endif + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, +@@ -815,11 +822,12 @@ + raw_close, + NULL, + raw_flush, +- ++#ifndef X49GP + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), ++#endif + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_getlength = raw_getlength, +diff -ur qemu-0.9.0/block-vvfat.c qemu/block-vvfat.c +--- qemu-0.9.0/block-vvfat.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-vvfat.c 2007-07-30 16:04:03.000000000 +0200 +@@ -41,9 +41,9 @@ + Note that DOS assumes the system files to be the first files in the + file system (test if the boot sector still relies on that fact)! */ + /* MAYBE TODO: write block-visofs.c */ +-/* TODO: call try_commit() only after a timeout */ + +-/* #define DEBUG */ ++#define DEBUG ++#undef DEBUG_SECTORS + + #ifdef DEBUG + +@@ -53,7 +53,7 @@ + #define stderr STDERR + FILE* stderr = NULL; + +-static void checkpoint(); ++static void checkpoint(const char *where); + + #ifdef __MINGW32__ + void nonono(const char* file, int line, const char* msg) { +@@ -70,9 +70,15 @@ + + #endif + ++#ifdef X49GP ++#define VOLUME_LABEL "X49GP-VVFAT" ++#else ++#define VOLUME_LABEL "QEMU-VVFAT" ++#endif ++ + /* dynamic array functions */ + typedef struct array_t { +- char* pointer; ++ unsigned char* pointer; + unsigned int size,next,item_size; + } array_t; + +@@ -144,9 +150,9 @@ + * index_to, but the order of all other elements is preserved. */ + static inline int array_roll(array_t* array,int index_to,int index_from,int count) + { +- char* buf; +- char* from; +- char* to; ++ unsigned char* buf; ++ unsigned char* from; ++ unsigned char* to; + int is; + + if(!array || +@@ -194,7 +200,7 @@ + /* return the index for a given member */ + int array_index(array_t* array, void* pointer) + { +- size_t offset = (char*)pointer - array->pointer; ++ size_t offset = (unsigned char*)pointer - array->pointer; + assert(offset >= 0); + assert((offset % array->item_size) == 0); + assert(offset/array->item_size < array->next); +@@ -204,6 +210,18 @@ + /* These structures are used to fake a disk and the VFAT filesystem. + * For this reason we need to use __attribute__((packed)). */ + ++#define BOOTCODE_SIZE 448 ++#define BOOTCODE_FAT32_SIZE 420 ++ ++typedef struct msdos_volume_info { ++ uint8_t drive_number; ++ uint8_t ignored; ++ uint8_t signature; ++ uint32_t id; ++ uint8_t volume_label[11]; ++ uint8_t fs_type[8]; ++} __attribute__((packed)) msdos_volume_info_t; ++ + typedef struct bootsector_t { + uint8_t jump[3]; + uint8_t name[8]; +@@ -221,11 +239,8 @@ + uint32_t total_sectors; + union { + struct { +- uint8_t drive_number; +- uint8_t current_head; +- uint8_t signature; +- uint32_t id; +- uint8_t volume_label[11]; ++ msdos_volume_info_t vi; ++ uint8_t boot_code[BOOTCODE_SIZE]; + } __attribute__((packed)) fat16; + struct { + uint32_t sectors_per_fat; +@@ -234,14 +249,43 @@ + uint32_t first_cluster_of_root_directory; + uint16_t info_sector; + uint16_t backup_boot_sector; +- uint16_t ignored; ++ uint16_t ignored[6]; ++ msdos_volume_info_t vi; ++ uint8_t boot_code[BOOTCODE_FAT32_SIZE]; + } __attribute__((packed)) fat32; + } u; +- uint8_t fat_type[8]; +- uint8_t ignored[0x1c0]; + uint8_t magic[2]; + } __attribute__((packed)) bootsector_t; + ++uint8_t dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 }; ++ ++uint8_t dummy_boot_code[BOOTCODE_SIZE] = ++ "\x0e" /* push cs */ ++ "\x1f" /* pop ds */ ++ "\xbe\x5b\x7c" /* mov si, */ ++/* write_msg: */ ++ "\xac" /* lodsb */ ++ "\x22\xc0" /* and al, al */ ++ "\x74\x0b" /* jz key_press */ ++ "\x56" /* push si */ ++ "\xb4\x0e" /* mov ah, 0eh */ ++ "\xbb\x07\x00" /* mov bx, 0007h */ ++ "\xcd\x10" /* int 10h */ ++ "\x5e" /* pop si */ ++ "\xeb\xf0" /* jmp write_msg */ ++/* key_press: */ ++ "\x32\xe4" /* xor ah, ah */ ++ "\xcd\x16" /* int 16h */ ++ "\xcd\x19" /* int 19h */ ++/* foo: */ ++ "\xeb\xfe" /* jmp foo */ ++/* message_text: */ ++ "This is not a bootable disk. Please insert a bootable floppy and\r\n" ++ "press any key to try again...\r\n"; ++ ++#define MSG_OFFSET_OFFSET 3 ++#define MESSAGE_OFFSET 29 /* Offset of message in above code */ ++ + typedef struct partition_t { + uint8_t attributes; /* 0x80 = bootable */ + uint8_t start_head; +@@ -340,7 +384,6 @@ + unsigned int current_cluster; + + /* write support */ +- BlockDriverState* write_target; + char* qcow_filename; + BlockDriverState* qcow; + void* fat2; +@@ -348,6 +391,7 @@ + array_t commits; + const char* path; + int downcase_short_names; ++ QEMUTimer *write_timer; + } BDRVVVFATState; + + +@@ -377,7 +421,7 @@ + /* direntry functions */ + + /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */ +-static inline int short2long_name(unsigned char* dest,const char* src) ++static inline int short2long_name(char* dest,const char* src) + { + int i; + for(i=0;i<129 && src[i];i++) { +@@ -423,7 +467,7 @@ + + static char is_volume_label(const direntry_t* direntry) + { +- return direntry->attributes == 0x28; ++ return (direntry->attributes & 0x1f) == 0x08; + } + + static char is_long_name(const direntry_t* direntry) +@@ -501,13 +545,16 @@ + { + if(s->fat_type==32) { + uint32_t* entry=array_get(&(s->fat),cluster); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %08x\n", __FUNCTION__, __LINE__, cluster, value)); + *entry=cpu_to_le32(value); + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %04x\n", __FUNCTION__, __LINE__, cluster, value & 0xffff)); + *entry=cpu_to_le16(value&0xffff); + } else { + int offset = (cluster*3/2); + unsigned char* p = array_get(&(s->fat), offset); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %03x\n", __FUNCTION__, __LINE__, cluster, value & 0xfff)); + switch (cluster&1) { + case 0: + p[0] = value&0xff; +@@ -561,7 +608,6 @@ + case 32: s->max_fat_value=0x0fffffff; break; + default: s->max_fat_value=0; /* error... */ + } +- + } + + /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ +@@ -575,7 +621,7 @@ + + if(is_dot) { + entry=array_get_next(&(s->directory)); +- memset(entry->name,0x20,11); ++ memset(entry->name,' ',11); + memcpy(entry->name,filename,strlen(filename)); + return entry; + } +@@ -590,8 +636,8 @@ + i = 8; + + entry=array_get_next(&(s->directory)); +- memset(entry->name,0x20,11); +- strncpy(entry->name,filename,i); ++ memset(entry->name,' ',11); ++ strncpy((char *) entry->name,filename,i); + + if(j > 0) + for (i = 0; i < 3 && filename[j+1+i]; i++) +@@ -700,6 +746,8 @@ + continue; + } + ++ DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); ++ + /* create directory entry for this file */ + direntry=create_short_and_long_name(s, i, entry->d_name, + is_dot || is_dotdot); +@@ -726,6 +774,8 @@ + + /* create mapping for this file */ + if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { ++ DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); ++ + s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); + s->current_mapping->begin=0; + s->current_mapping->end=st.st_size; +@@ -778,9 +828,9 @@ + return 0; + } + +-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) ++static inline int32_t sector2cluster(BDRVVVFATState* s, off_t sector_num) + { +- return (sector_num-s->faked_sectors)/s->sectors_per_cluster; ++ return (sector_num - s->faked_sectors) / s->sectors_per_cluster; + } + + static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) +@@ -805,15 +855,19 @@ + static int init_directories(BDRVVVFATState* s, + const char* dirname) + { ++ msdos_volume_info_t *vi; + bootsector_t* bootsector; + mapping_t* mapping; + unsigned int i; + unsigned int cluster; ++ direntry_t *entry; ++ struct stat st; ++ size_t namelen; + + memset(&(s->first_sectors[0]),0,0x40*0x200); + +- s->cluster_size=s->sectors_per_cluster*0x200; +- s->cluster_buffer=malloc(s->cluster_size); ++ s->cluster_size = s->sectors_per_cluster * 0x200; ++ s->cluster_buffer = malloc(s->cluster_size); + assert(s->cluster_buffer); + + /* +@@ -823,18 +877,32 @@ + * spc is sectors_per_clusters, and + * fat_type = 12, 16 or 32. + */ +- i = 1+s->sectors_per_cluster*0x200*8/s->fat_type; +- s->sectors_per_fat=(s->sector_count+i)/i; /* round up */ ++ i = 1 + s->sectors_per_cluster * 0x200 * 8 / s->fat_type; ++ s->sectors_per_fat = (s->sector_count + i) / i; /* round up */ + + array_init(&(s->mapping),sizeof(mapping_t)); + array_init(&(s->directory),sizeof(direntry_t)); + ++ DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, dirname)); ++ + /* add volume label */ +- { +- direntry_t* entry=array_get_next(&(s->directory)); +- entry->attributes=0x28; /* archive | volume label */ +- snprintf(entry->name,11,"QEMU VVFAT"); +- } ++ stat(dirname, &st); ++ entry = array_get_next(&(s->directory)); ++ entry->attributes = 0x08; /* archive | volume label */ ++ memset(entry->name, ' ', 11); ++ namelen = strlen(VOLUME_LABEL); ++ if (namelen > 11) ++ namelen = 11; ++ memcpy(entry->name, VOLUME_LABEL, namelen); ++ entry->reserved[0] = entry->reserved[1] = 0; ++ entry->ctime = fat_datetime(st.st_ctime, 1); ++ entry->cdate = fat_datetime(st.st_ctime, 0); ++ entry->adate = fat_datetime(st.st_atime, 0); ++ entry->begin_hi = 0; ++ entry->mtime = fat_datetime(st.st_ctime, 1); ++ entry->mdate = fat_datetime(st.st_ctime, 0); ++ entry->begin = 0; ++ entry->size = 0; + + /* Now build FAT, and write back information into directory */ + init_fat(s); +@@ -842,6 +910,8 @@ + s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2; + s->cluster_count=sector2cluster(s, s->sector_count); + ++ DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, dirname)); ++ + mapping = array_get_next(&(s->mapping)); + mapping->begin = 0; + mapping->dir_index = 0; +@@ -910,16 +980,39 @@ + s->last_cluster_of_root_directory = mapping->end; + + /* the FAT signature */ +- fat_set(s,0,s->max_fat_value); ++ switch (s->fat_type) { ++ case 12: fat_set(s, 0, s->sector_count == 5760 ? 0xff9 : 0xff8); break; ++ case 16: fat_set(s, 0, 0xfff8); break; ++ case 32: fat_set(s, 0, 0x0ffffff0); break; ++ default: fat_set(s,0,s->max_fat_value); break; ++ } + fat_set(s,1,s->max_fat_value); + + s->current_mapping = NULL; + + bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200); +- bootsector->jump[0]=0xeb; +- bootsector->jump[1]=0x3e; +- bootsector->jump[2]=0x90; ++ ++ memcpy(bootsector->jump, dummy_boot_jump, 3); ++ bootsector->jump[1] = ((s->fat_type == 32 ? ++ (char *) &bootsector->u.fat32.boot_code : ++ (char *) &bootsector->u.fat16.boot_code) - ++ (char *) &bootsector) - 2; ++ if (s->fat_type == 32) { ++ int offset = (char *) &bootsector->u.fat32.boot_code - ++ (char *) &bootsector + MESSAGE_OFFSET + 0x7c00; ++ memcpy(bootsector->u.fat32.boot_code, dummy_boot_code, ++ BOOTCODE_FAT32_SIZE); ++ bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 0] = offset & 0xff; ++ bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 1] = offset >> 8; ++ } else { ++ memcpy(bootsector->u.fat16.boot_code, dummy_boot_code, BOOTCODE_SIZE); ++ } ++ ++#ifdef X49GP ++ memcpy(bootsector->name,"X49GP ",8); ++#else + memcpy(bootsector->name,"QEMU ",8); ++#endif + bootsector->sector_size=cpu_to_le16(0x200); + bootsector->sectors_per_cluster=s->sectors_per_cluster; + bootsector->reserved_sectors=cpu_to_le16(1); +@@ -927,7 +1020,6 @@ + bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); + bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); + bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */ +- s->fat.pointer[0] = bootsector->media_type; + bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); + bootsector->sectors_per_track=cpu_to_le16(s->bs->secs); + bootsector->number_of_heads=cpu_to_le16(s->bs->heads); +@@ -935,15 +1027,25 @@ + bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); + + /* LATER TODO: if FAT32, this is wrong */ +- bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */ +- bootsector->u.fat16.current_head=0; +- bootsector->u.fat16.signature=0x29; +- bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); ++ if (s->fat_type == 32) { ++ vi = &bootsector->u.fat32.vi; ++ memcpy(vi->fs_type, "FAT32 ", 8); ++ } else { ++ vi = &bootsector->u.fat16.vi; ++ memcpy(vi->fs_type, (s->fat_type == 12 ? "FAT12 " : "FAT16 "), 8); ++ } + +- memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11); +- memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8); +- bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; ++ /* assume this is hda (TODO) */ ++ vi->drive_number = s->fat_type == 12 ? 0 : 0x80; ++ vi->signature = 0x29; ++ vi->id = cpu_to_le32(0xfabe1afd); ++ memset(vi->volume_label, ' ', 11); ++ namelen = strlen(VOLUME_LABEL); ++ if (namelen > 11) ++ namelen = 11; ++ memcpy(vi->volume_label, VOLUME_LABEL, namelen); + ++ bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; + return 0; + } + +@@ -951,7 +1053,7 @@ + static BDRVVVFATState *vvv = NULL; + #endif + +-static int enable_write_target(BDRVVVFATState *s); ++static int enable_write(BDRVVVFATState *s); + static int is_consistent(BDRVVVFATState *s); + + static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags) +@@ -964,10 +1066,10 @@ + vvv = s; + #endif + +-DLOG(if (stderr == NULL) { +- stderr = fopen("vvfat.log", "a"); +- setbuf(stderr, NULL); +-}) ++ DLOG(if (stderr == NULL) { ++ stderr = fopen("vvfat.log", "a"); ++ setbuf(stderr, NULL); ++ }) + + s->bs = bs; + +@@ -983,17 +1085,20 @@ + s->first_sectors_number=0x40; + /* read only is the default for safety */ + bs->read_only = 1; +- s->qcow = s->write_target = NULL; ++ s->qcow = NULL; + s->qcow_filename = NULL; + s->fat2 = NULL; + s->downcase_short_names = 1; + +- if (!strstart(dirname, "fat:", NULL)) ++ if (!strstart(dirname, "fat:", NULL)) { ++ DLOG(fprintf(stderr, "%s:%u: dirname '%s' not \"fat:\"\n", __FUNCTION__, __LINE__, dirname)); + return -1; ++ } + + if (strstr(dirname, ":rw:")) { +- if (enable_write_target(s)) ++ if (enable_write(s)) { + return -1; ++ } + bs->read_only = 0; + } + +@@ -1026,8 +1131,11 @@ + bs->total_sectors=bs->cyls*bs->heads*bs->secs; + if (s->sector_count > bs->total_sectors) + s->sector_count = bs->total_sectors; +- if(init_directories(s, dirname)) ++ ++ if (init_directories(s, dirname)) { ++ DLOG(fprintf(stderr, "%s:%u: init_directories failed\n", __FUNCTION__, __LINE__)); + return -1; ++ } + + if(s->first_sectors_number==0x40) + init_mbr(s); +@@ -1037,6 +1145,8 @@ + bs->heads = bs->cyls = bs->secs = 0; + + // assert(is_consistent(s)); ++ ++ DLOG(fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__)); + return 0; + } + +@@ -1153,7 +1263,7 @@ + s->cluster = s->directory.pointer+offset + + 0x20*s->current_mapping->info.dir.first_dir_index; + assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); +- assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); ++ assert(s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); + s->current_cluster = cluster_num; + return 0; + } +@@ -1227,6 +1337,18 @@ + direntry->attributes, + begin_of_direntry(direntry),le32_to_cpu(direntry->size)); + } ++ { ++ unsigned char *p = (void *) direntry; ++ int i; ++ ++ fprintf(stderr, "%p:\t", p); ++ for (i = 0; i < 16; i++) ++ fprintf(stderr, " %02x", *p++); ++ fprintf(stderr, "\n%p:\t", p); ++ for ( ; i < 32; i++) ++ fprintf(stderr, " %02x", *p++); ++ fprintf(stderr, "\n"); ++ } + } + + static void print_mapping(const mapping_t* mapping) +@@ -1243,6 +1365,9 @@ + uint8_t *buf, int nb_sectors) + { + BDRVVVFATState *s = bs->opaque; ++#ifdef DEBUG_SECTORS ++ int32_t orig_sector = sector_num; ++#endif + int i; + + for(i=0;ifaked_sectors) { + if(sector_numfirst_sectors_number) +@@ -1280,6 +1405,14 @@ + memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); + } + } ++ ++#ifdef DEBUG_SECTORS ++ for (i = 0; i < nb_sectors; i++) { ++ fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); ++ hexdump(buf + i * 0x200, 0x200); ++ } ++#endif ++ + return 0; + } + +@@ -1372,7 +1505,7 @@ + } + + typedef struct { +- unsigned char name[1024]; ++ char name[1024]; + int checksum, len; + int sequence_number; + } long_file_name; +@@ -1577,6 +1710,7 @@ + const char* basename; + + assert(mapping->mode & MODE_DELETED); ++ DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + basename = get_basename(mapping->path); +@@ -1702,6 +1836,7 @@ + assert(mapping->mode & MODE_DIRECTORY); + + assert(mapping->mode & MODE_DELETED); ++ DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + if (strcmp(basename, basename2)) +@@ -1736,9 +1871,9 @@ + for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { + int cluster_count; + +-DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)); +- if (is_volume_label(direntries + i) || is_dot(direntries + i) || +- is_free(direntries + i)) ++DLOG(if (!is_free(direntries + i)) { fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i); }) ++ ++ if (is_volume_label(direntries + i) || is_dot(direntries + i) || is_free(direntries + i)) + continue; + + subret = parse_long_name(&lfn, direntries + i); +@@ -1806,7 +1941,10 @@ + int i, check; + int used_clusters_count = 0; + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ + /* + * - get modified FAT + * - compare the two FATs (TODO) +@@ -1825,10 +1963,11 @@ + s->fat2 = malloc(size); + memcpy(s->fat2, s->fat.pointer, size); + } +- check = vvfat_read(s->bs, +- s->first_sectors_number, s->fat2, s->sectors_per_fat); ++ check = vvfat_read(s->bs, s->first_sectors_number, ++ s->fat2, s->sectors_per_fat); + if (check) { + fprintf(stderr, "Could not copy fat\n"); ++ DLOG(fprintf(stderr, "%s:%u: copy fat failed\n", __FUNCTION__, __LINE__)); + return 0; + } + assert (s->used_clusters); +@@ -1839,12 +1978,15 @@ + + /* mark every mapped file/directory as deleted. + * (check_directory_consistency() will unmark those still present). */ +- if (s->qcow) ++ if (s->qcow) { + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); +- if (mapping->first_mapping_index < 0) ++ if (mapping->first_mapping_index < 0) { ++ DLOG(fprintf(stderr, "%s:%u: mark delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode |= MODE_DELETED; ++ } + } ++ } + + used_clusters_count = check_directory_consistency(s, 0, s->path); + if (used_clusters_count <= 0) { +@@ -1869,9 +2011,12 @@ + } + } + +- if (check != used_clusters_count) ++ if (check != used_clusters_count) { ++ DLOG(fprintf(stderr, "%s:%u: check: %u, used %u\n", __FUNCTION__, __LINE__, check, used_clusters_count)); + return 0; ++ } + ++ DLOG(fprintf(stderr, "%s:%u: return used %u\n", __FUNCTION__, __LINE__, used_clusters_count)); + return used_clusters_count; + } + +@@ -1928,6 +2073,8 @@ + ((next_mapping = array_get(&(s->mapping), index + 1)) && + next_mapping->begin >= end))); + ++ DLOG(fprintf(stderr, "insert mapping %u:\n", index); print_mapping(mapping)); ++ + if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) + s->current_mapping = array_get(&(s->mapping), + s->current_mapping - first_mapping); +@@ -1940,6 +2087,8 @@ + mapping_t* mapping = array_get(&(s->mapping), mapping_index); + mapping_t* first_mapping = array_get(&(s->mapping), 0); + ++ DLOG(fprintf(stderr, "remove mapping %u:\n", mapping_index); print_mapping(mapping)); ++ + /* free mapping */ + if (mapping->first_mapping_index < 0) + free(mapping->path); +@@ -2090,7 +2239,7 @@ + int ret, i; + uint32_t c; + +-DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index)); ++ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index)); + + assert(direntry); + assert(mapping); +@@ -2130,7 +2279,7 @@ + s->sectors_per_cluster); + if (ret) + return ret; +- assert(!strncmp(s->directory.pointer, "QEMU", 4)); ++ assert(!strncmp((char *) s->directory.pointer, VOLUME_LABEL, strlen(VOLUME_LABEL))); + current_dir_index += factor; + } + +@@ -2164,7 +2313,7 @@ + uint32_t first_cluster = c; + mapping_t* mapping = find_mapping_for_cluster(s, c); + uint32_t size = filesize_of_direntry(direntry); +- char* cluster = malloc(s->cluster_size); ++ unsigned char* cluster = malloc(s->cluster_size); + uint32_t i; + int fd = 0; + +@@ -2217,13 +2366,13 @@ + + #ifdef DEBUG + /* test, if all mappings point to valid direntries */ +-static void check1(BDRVVVFATState* s) ++static void check1(BDRVVVFATState* s, const char *where) + { + int i; + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { +- fprintf(stderr, "deleted\n"); ++ DLOG(fprintf(stderr, "%s: deleted\n", where); print_mapping(mapping)); + continue; + } + assert(mapping->dir_index >= 0); +@@ -2238,7 +2387,7 @@ + } + + /* test, if all direntries have mappings */ +-static void check2(BDRVVVFATState* s) ++static void check2(BDRVVVFATState* s, const char *where) + { + int i; + int first_mapping = -1; +@@ -2485,7 +2634,9 @@ + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { + direntry_t* entry = array_get(&(s->directory), +- mapping->dir_index); ++ mapping->dir_index); ++ ++ DLOG(fprintf(stderr, "%s:%u: ", __FUNCTION__, __LINE__); print_mapping(mapping); print_direntry(entry)); + + if (is_free(entry)) { + /* remove file/directory */ +@@ -2515,14 +2666,15 @@ + next_dir_index - first_dir_index); + + deleted++; ++ } else { ++ if (unlink(mapping->path)) ++ return -4; ++ deleted++; + } +- } else { +- if (unlink(mapping->path)) +- return -4; +- deleted++; ++ ++ DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); ++ remove_mapping(s, i); + } +- DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); +- remove_mapping(s, i); + } + } + } +@@ -2530,6 +2682,20 @@ + return 0; + } + ++static int have_deletes(BDRVVVFATState* s) ++{ ++ int i; ++ ++ for (i = 0; i < s->mapping.next; i++) { ++ mapping_t* mapping = array_get(&(s->mapping), i); ++ if (mapping->mode & MODE_DELETED) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ + /* + * synchronize mapping with new state: + * +@@ -2543,8 +2709,10 @@ + int ret = 0; + + /* the real meat are the commits. Nothing to do? Move along! */ +- if (s->commits.next == 0) ++ if ((0 == s->commits.next) && (0 == have_deletes(s))) { ++ DLOG(fprintf(stderr, "%s:%u: nothing to do\n", __FUNCTION__, __LINE__)); + return 0; ++ } + + vvfat_close_current_file(s); + +@@ -2584,26 +2752,48 @@ + + memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); + return 0; + } + + static int try_commit(BDRVVVFATState* s) + { + vvfat_close_current_file(s); +-DLOG(checkpoint()); ++ ++DLOG(checkpoint(__FUNCTION__)); ++ + if(!is_consistent(s)) + return -1; ++ + return do_commit(s); + } + ++static void ++vvfat_write_timer(void *opaque) ++{ ++ BDRVVVFATState *s = opaque; ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ ++DLOG(checkpoint("vvfat_write_timer: before try_commits")); ++ ++ try_commit(s); ++ ++DLOG(checkpoint("vvfat_write_timer: after try_commits")); ++} ++ + static int vvfat_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) + { + BDRVVVFATState *s = bs->opaque; ++ mapping_t* mapping; ++#ifdef DEBUG_SECTORS ++ int32_t orig_sector = sector_num; ++#endif ++ int64_t start_cluster, end_cluster; + int i, ret; + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); + + vvfat_close_current_file(s); + +@@ -2613,12 +2803,35 @@ + * - do not allow to write non-ASCII filenames + */ + +- if (sector_num < s->first_sectors_number) ++ if (sector_num < s->first_sectors_number) { ++ DLOG(fprintf(stderr, "%s:%u: sector: %u nb %u (first: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->first_sectors_number)); + return -1; ++ } + +- for (i = sector2cluster(s, sector_num); +- i <= sector2cluster(s, sector_num + nb_sectors - 1);) { +- mapping_t* mapping = find_mapping_for_cluster(s, i); ++#ifdef DEBUG_SECTORS ++ for (i = 0; i < nb_sectors; i++) { ++ fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); ++ hexdump(buf + i * 0x200, 0x200); ++ } ++#endif ++ ++ DLOG(fprintf(stderr, "%s:%u: check mappings, sector: %u nb %u (faked: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->faked_sectors)); ++ ++ if (sector_num >= s->faked_sectors) { ++ start_cluster = sector2cluster(s, sector_num); ++ } else { ++ start_cluster = 0; ++ } ++ if (sector_num + nb_sectors - 1 >= s->faked_sectors) { ++ end_cluster = sector2cluster(s, sector_num + nb_sectors - 1); ++ } else { ++ end_cluster = -1; ++ } ++ ++ for (i = start_cluster; i <= end_cluster; ) { ++ DLOG(fprintf(stderr, "%s:%u: cluster %u\n", __FUNCTION__, __LINE__, i)); ++ mapping = find_mapping_for_cluster(s, i); ++ DLOG(fprintf(stderr, "%s:%u: mapping %p\n", __FUNCTION__, __LINE__, mapping)); + if (mapping) { + if (mapping->read_only) { + fprintf(stderr, "Tried to write to write-protected file %s\n", +@@ -2662,30 +2875,25 @@ + } + } + i = mapping->end; +- } else ++ } else { + i++; ++ } + } + + /* + * Use qcow backend. Commit later. + */ +-DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); ++ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); + ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors); + if (ret < 0) { + fprintf(stderr, "Error writing to qcow backend\n"); + return ret; + } + +- for (i = sector2cluster(s, sector_num); +- i <= sector2cluster(s, sector_num + nb_sectors - 1); i++) +- if (i >= 0) +- s->used_clusters[i] |= USED_ALLOCATED; +- +-DLOG(checkpoint()); +- /* TODO: add timeout */ +- try_commit(s); ++ for (i = start_cluster; i <= end_cluster; i++) ++ s->used_clusters[i] |= USED_ALLOCATED; + +-DLOG(checkpoint()); ++ qemu_mod_timer(s->write_timer, qemu_get_clock(rt_clock) + ticks_per_sec); + return 0; + } + +@@ -2701,49 +2909,62 @@ + return 1; + } + +-static int write_target_commit(BlockDriverState *bs, int64_t sector_num, +- const uint8_t* buffer, int nb_sectors) { +- BDRVVVFATState* s = bs->opaque; +- return try_commit(s); +-} +- +-static void write_target_close(BlockDriverState *bs) { +- BDRVVVFATState* s = bs->opaque; +- bdrv_delete(s->qcow); +- free(s->qcow_filename); +-} +- +-static BlockDriver vvfat_write_target = { +- "vvfat_write_target", 0, NULL, NULL, NULL, +- write_target_commit, +- write_target_close, +- NULL, NULL, NULL +-}; +- +-static int enable_write_target(BDRVVVFATState *s) ++static int enable_write(BDRVVVFATState *s) + { +- int size = sector2cluster(s, s->sector_count); ++ int error; ++ int size; ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ ++ size = sector2cluster(s, s->sector_count); + s->used_clusters = calloc(size, 1); + + array_init(&(s->commits), sizeof(commit_t)); + + s->qcow_filename = malloc(1024); + get_tmp_filename(s->qcow_filename, 1024); +- if (bdrv_create(&bdrv_qcow, +- s->qcow_filename, s->sector_count, "fat:", 0) < 0) ++ error = bdrv_create(&bdrv_qcow, s->qcow_filename, s->sector_count, "", 0); ++ if (error < 0) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_create '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); + return -1; ++ } ++ + s->qcow = bdrv_new(""); +- if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0) ++ if (s->qcow == NULL) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_new: Out of memory\n", __FUNCTION__, __LINE__)); ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif + return -1; ++ } + ++ error = bdrv_open(s->qcow, s->qcow_filename, 0); ++ if (error < 0) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_open '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); + #ifndef _WIN32 +- unlink(s->qcow_filename); ++ unlink(s->qcow_filename); + #endif ++ bdrv_delete(s->qcow); ++ return -1; ++ } + +- s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1); +- s->bs->backing_hd->drv = &vvfat_write_target; +- s->bs->backing_hd->opaque = s; ++ s->write_timer = qemu_new_timer(rt_clock, vvfat_write_timer, s); ++ if (NULL == s->write_timer) { ++ DLOG(fprintf(stderr, "%s:%u: write_timer: Out of memory\n", __FUNCTION__, __LINE__)); ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif ++ bdrv_delete(s->qcow); ++ return -1; ++ } ++ ++ s->qcow->is_temporary = 1; ++ ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif + ++ DLOG(fprintf(stderr, "%s:%u: write enabled\n", __FUNCTION__, __LINE__)); + return 0; + } + +@@ -2751,10 +2972,24 @@ + { + BDRVVVFATState *s = bs->opaque; + ++ if (qemu_timer_pending(s->write_timer)) { ++ qemu_del_timer(s->write_timer); ++ vvfat_write_timer(s); ++ } ++ + vvfat_close_current_file(s); ++ ++ if (s->qcow) { ++ qemu_free(s->qcow_filename); ++ ++ bdrv_delete(s->qcow); ++ s->qcow = NULL; ++ } ++ + array_free(&(s->fat)); + array_free(&(s->directory)); + array_free(&(s->mapping)); ++ + if(s->cluster_buffer) + free(s->cluster_buffer); + } +@@ -2774,10 +3009,16 @@ + }; + + #ifdef DEBUG +-static void checkpoint() { ++static void ++checkpoint(const char *where) ++{ ++ DLOG(fprintf(stderr, "%s:%u: checkpoint(%s)\n", __FUNCTION__, __LINE__, where)); ++ + assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); +- check1(vvv); +- check2(vvv); ++ DLOG(fprintf(stderr, "checkpoint(%s): call check1()\n", where)); ++ check1(vvv, where); ++ DLOG(fprintf(stderr, "checkpoint(%s): call check2()\n", where)); ++ check2(vvv, where); + assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); + #if 0 + if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf) +@@ -2793,10 +3034,11 @@ + direntry = array_get(&(vvv->directory), mapping->dir_index); + assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0); + #endif ++ DLOG(fprintf(stderr, "checkpoint(%s): done\n", where)); + return; + /* avoid compiler warnings: */ + hexdump(NULL, 100); +- remove_mapping(vvv, NULL); ++ remove_mapping(vvv, 0); + print_mapping(NULL); + print_direntry(NULL); + } diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-build-libqemu.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-build-libqemu.patch.svn-base new file mode 100644 index 0000000..06f72ba --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-build-libqemu.patch.svn-base @@ -0,0 +1,15 @@ +--- qemu-0.9.0/Makefile 2007-07-26 11:10:25.000000000 +0200 ++++ qemu/Makefile 2007-07-26 11:10:38.000000000 +0200 +@@ -32,10 +32,10 @@ + endif + endif + +-all: $(TOOLS) $(DOCS) recurse-all ++all: recurse-all + + subdir-%: dyngen$(EXESUF) +- $(MAKE) -C $(subst subdir-,,$@) all ++ $(MAKE) -C $(subst subdir-,,$@) libqemu.a + + recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) + diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-debug-unassigned.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-debug-unassigned.patch.svn-base new file mode 100644 index 0000000..9fca6a1 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-debug-unassigned.patch.svn-base @@ -0,0 +1,36 @@ +diff -ur qemu/exec.c qemu-0.9.0/exec.c +--- qemu/exec.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/exec.c 2007-07-10 09:14:31.000000000 +0200 +@@ -41,7 +41,7 @@ + //#define DEBUG_TB_INVALIDATE + //#define DEBUG_FLUSH + //#define DEBUG_TLB +-//#define DEBUG_UNASSIGNED ++#define DEBUG_UNASSIGNED + + /* make various TB consistency checks */ + //#define DEBUG_TB_CHECK +@@ -1812,10 +1812,14 @@ + return p->phys_offset; + } + ++CPUState *__GLOBAL_env; ++ + static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) + { + #ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read 0x%08x\n", (int)addr); ++ cpu_dump_state(__GLOBAL_env, stdout, fprintf, 0); ++ abort(); + #endif + return 0; + } +@@ -1824,6 +1828,8 @@ + { + #ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); ++ cpu_dump_state(__GLOBAL_env, stdout, fprintf, 0); ++ abort(); + #endif + } + diff --git a/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-phys_ram_dirty.patch.svn-base b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-phys_ram_dirty.patch.svn-base new file mode 100644 index 0000000..cdb7db6 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-0.9.0-x49gp-phys_ram_dirty.patch.svn-base @@ -0,0 +1,17 @@ +--- qemu-0.9.0/exec.c 2007-07-23 13:57:29.000000000 +0200 ++++ qemu/exec.c 2007-07-23 13:53:06.000000000 +0200 +@@ -1942,9 +1942,11 @@ + cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); + io_mem_nb = 5; + +- /* alloc dirty bits array */ +- phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); +- memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); ++ if (phys_ram_size) { ++ /* alloc dirty bits array */ ++ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); ++ memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); ++ } + } + + /* mem_read and mem_write are arrays of functions containing the diff --git a/qemu/patches/.svn/text-base/qemu-2ndbootdevice_04.diff.svn-base b/qemu/patches/.svn/text-base/qemu-2ndbootdevice_04.diff.svn-base new file mode 100644 index 0000000..4220ec9 --- /dev/null +++ b/qemu/patches/.svn/text-base/qemu-2ndbootdevice_04.diff.svn-base @@ -0,0 +1,165 @@ +--- vl.h 2007-02-05 21:20:30.000000000 +0100 ++++ vl.h_2 2007-03-14 16:22:14.000000000 +0100 +@@ -683,6 +683,9 @@ + + typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, + int boot_device, ++#ifdef TARGET_I386 ++ int boot_device_2, ++#endif + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +--- vl.c 2007-02-05 21:46:05.000000000 +0100 ++++ vl.c_2.c 2007-03-14 15:16:49.000000000 +0100 +@@ -131,6 +131,7 @@ + const char* keyboard_layout = NULL; + int64_t ticks_per_sec; + int boot_device = 'c'; ++int boot_device_2 = 'd'; + int ram_size; + int pit_min_timer_count = 0; + int nb_nics; +@@ -6021,7 +6022,11 @@ + "-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 image (cdrom is ide1 master)\n" ++#ifdef TARGET_I386 ++ "-boot d1(,d2) boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" ++#else + "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" ++#endif + "-snapshot write to temporary files instead of disk image files\n" + #ifdef CONFIG_SDL + "-no-quit disable SDL window close capability\n" +@@ -6721,6 +6734,15 @@ + break; + case QEMU_OPTION_boot: + boot_device = optarg[0]; ++#ifdef TARGET_I386 ++ if (strlen(optarg) == 3) { //we have a second bootdevice ++ boot_device_2 = optarg[2]; ++ if (boot_device_2 != 'a' && boot_device_2 != 'c' && boot_device_2 != 'd') { ++ fprintf(stderr, "qemu: invalid second boot device '%c'\n", boot_device_2); ++ exit(1); ++ } ++ } ++#endif + if (boot_device != 'a' && + #if defined(TARGET_SPARC) || defined(TARGET_I386) + // Network boot +@@ -7199,8 +7220,11 @@ + qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); + } + } +- ++#ifdef TARGET_I386 ++ machine->init(ram_size, vga_ram_size, boot_device, boot_device_2, ++#else + machine->init(ram_size, vga_ram_size, boot_device, ++#endif + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); + +--- hw/pc.c 2007-02-02 04:13:18.000000000 +0100 ++++ hw/pc.c_2 2007-03-14 15:58:38.000000000 +0100 +@@ -154,7 +154,7 @@ + } + + /* hd_table must contain 4 block drivers */ +-static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) ++static void cmos_init(int ram_size, int boot_device, int boot_device_2, BlockDriverState **hd_table) + { + RTCState *s = rtc_state; + int val; +@@ -185,19 +185,32 @@ + rtc_set_memory(s, 0x34, val); + rtc_set_memory(s, 0x35, val >> 8); + ++ int bd2_val; ++ switch(boot_device_2) { ++ case 'a': ++ bd2_val = 0x10; ++ break; ++ case 'c': ++ bd2_val = 0x20; ++ break; ++ case 'd': ++ bd2_val = 0x30; ++ break; ++ } ++ + switch(boot_device) { + case 'a': + case 'b': +- rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x01); /* floppy boot */ + if (!fd_bootchk) +- rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ ++ rtc_set_memory(s, 0x38, bd2_val | 0x01); /* disable signature check */ + break; + default: + case 'c': +- rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x02); /* hard drive boot */ + break; + case 'd': +- rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x03); /* CD-ROM boot */ + break; + } + +@@ -443,7 +459,8 @@ + } + + /* PC hardware initialisation */ +-static void pc_init1(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init1(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, +@@ -692,7 +709,7 @@ + + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + +- cmos_init(ram_size, boot_device, bs_table); ++ cmos_init(ram_size, boot_device, boot_device_2, bs_table); + + if (pci_enabled && usb_enabled) { + usb_uhci_init(pci_bus, piix3_devfn + 2); +@@ -730,27 +747,29 @@ + #endif + } + +-static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init_pci(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) + { +- pc_init1(ram_size, vga_ram_size, boot_device, ++ pc_init1(ram_size, vga_ram_size, boot_device, boot_device_2, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 1); + } + +-static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init_isa(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) + { +- pc_init1(ram_size, vga_ram_size, boot_device, ++ pc_init1(ram_size, vga_ram_size, boot_device, boot_device_2, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0); diff --git a/qemu/patches/CVS/.svn/all-wcprops b/qemu/patches/CVS/.svn/all-wcprops new file mode 100644 index 0000000..cd3534f --- /dev/null +++ b/qemu/patches/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 41 +/p/x49gp/code/!svn/ver/1/qemu/patches/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/1/qemu/patches/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/1/qemu/patches/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/1/qemu/patches/CVS/Entries +END diff --git a/qemu/patches/CVS/.svn/entries b/qemu/patches/CVS/.svn/entries new file mode 100644 index 0000000..77dcf7b --- /dev/null +++ b/qemu/patches/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/patches/CVS +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +Repository +file + + + + +2013-08-23T00:54:47.000000Z +4c063d3977ba502043820ee925891780 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +19 + +Root +file + + + + +2013-08-23T00:54:47.000000Z +f51b768066a9e7d88829b19678326fcd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +60 + +Entries +file + + + + +2013-08-23T00:54:47.000000Z +d8b5b85ba4644b924f6616d6a7a89073 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +1647 + diff --git a/qemu/patches/CVS/.svn/text-base/Entries.svn-base b/qemu/patches/CVS/.svn/text-base/Entries.svn-base new file mode 100644 index 0000000..3a2dc7e --- /dev/null +++ b/qemu/patches/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,27 @@ +/q_block.c_hdled_1.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_block_int.h_hdled_1.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_host-cocoa_02.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_vga.c_02.diff/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.7.2-dyngen-check-stack-clobbers.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.7.2-gcc4-opts.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.8.0-gcc4-hacks.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.8.0-osx-bugfix.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-arm-shift.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-enforce-16byte-stack-boundary.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-gcc4.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-i386-FORCE_RET.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-osx-intel-port.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-qcow2.diff/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-clobber.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-compile-flags.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-load-store-le.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-register.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-dump-state.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-mmu.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-semihosting.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-block.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-build-libqemu.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-debug-unassigned.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-phys_ram_dirty.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-2ndbootdevice_04.diff/1.1/Thu Dec 11 12:14:09 2008// +D diff --git a/qemu/patches/CVS/.svn/text-base/Repository.svn-base b/qemu/patches/CVS/.svn/text-base/Repository.svn-base new file mode 100644 index 0000000..2413c0a --- /dev/null +++ b/qemu/patches/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +x49gp/qemu/patches diff --git a/qemu/patches/CVS/.svn/text-base/Root.svn-base b/qemu/patches/CVS/.svn/text-base/Root.svn-base new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/qemu/patches/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/qemu/patches/CVS/Entries b/qemu/patches/CVS/Entries new file mode 100644 index 0000000..3a2dc7e --- /dev/null +++ b/qemu/patches/CVS/Entries @@ -0,0 +1,27 @@ +/q_block.c_hdled_1.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_block_int.h_hdled_1.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_host-cocoa_02.diff/1.1/Thu Dec 11 12:14:08 2008// +/q_vga.c_02.diff/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.7.2-dyngen-check-stack-clobbers.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.7.2-gcc4-opts.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.8.0-gcc4-hacks.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.8.0-osx-bugfix.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-arm-shift.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-enforce-16byte-stack-boundary.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-gcc4.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-i386-FORCE_RET.patch/1.1/Thu Dec 11 12:14:08 2008// +/qemu-0.9.0-osx-intel-port.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-qcow2.diff/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-clobber.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-compile-flags.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-load-store-le.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-sparc-register.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-dump-state.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-mmu.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-arm-semihosting.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-block.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-build-libqemu.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-debug-unassigned.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-0.9.0-x49gp-phys_ram_dirty.patch/1.1/Thu Dec 11 12:14:09 2008// +/qemu-2ndbootdevice_04.diff/1.1/Thu Dec 11 12:14:09 2008// +D diff --git a/qemu/patches/CVS/Repository b/qemu/patches/CVS/Repository new file mode 100644 index 0000000..2413c0a --- /dev/null +++ b/qemu/patches/CVS/Repository @@ -0,0 +1 @@ +x49gp/qemu/patches diff --git a/qemu/patches/CVS/Root b/qemu/patches/CVS/Root new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/qemu/patches/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/qemu/patches/q_block.c_hdled_1.diff b/qemu/patches/q_block.c_hdled_1.diff new file mode 100644 index 0000000..ad53ba8 --- /dev/null +++ b/qemu/patches/q_block.c_hdled_1.diff @@ -0,0 +1,34 @@ +--- block.c 2007-02-06 02:15:39.000000000 +0100 ++++ block2.c 2007-02-06 02:24:10.000000000 +0100 +@@ -497,6 +497,7 @@ + int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) +@@ -534,6 +535,7 @@ + int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + if (!bs->drv) + return -ENOMEDIUM; +@@ -1058,6 +1060,7 @@ + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) +@@ -1078,6 +1081,7 @@ + const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) + { ++ bs->activityLED = 1; + BlockDriver *drv = bs->drv; + + if (!drv) diff --git a/qemu/patches/q_block_int.h_hdled_1.diff b/qemu/patches/q_block_int.h_hdled_1.diff new file mode 100644 index 0000000..835d7fb --- /dev/null +++ b/qemu/patches/q_block_int.h_hdled_1.diff @@ -0,0 +1,10 @@ +--- block_int.h 2006-06-21 18:46:53.000000000 +0200 ++++ block_int2.h 2006-07-03 17:20:04.000000000 +0200 +@@ -51,6 +51,7 @@ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ ++ int activityLED; /* if true, the media is accessed atm */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; diff --git a/qemu/patches/q_host-cocoa_02.diff b/qemu/patches/q_host-cocoa_02.diff new file mode 100644 index 0000000..0423bba --- /dev/null +++ b/qemu/patches/q_host-cocoa_02.diff @@ -0,0 +1,26 @@ +--- Makefile.target 2007-01-31 13:24:18.000000000 +0100 ++++ Makefile.target 2007-02-02 14:45:02.000000000 +0100 +@@ -415,8 +419,8 @@ + endif + VL_OBJS+=vnc.o + ifdef CONFIG_COCOA +-VL_OBJS+=cocoa.o +-COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit ++VL_OBJS+=cocoaQemuMain.o cocoaQemuController.o cocoaQemu.o cocoaQemuProgressWindow.o cocoaQemuWindow.o cocoaQemuOpenGLView.o cocoaQemuQuartzView.o cocoaQemuQuickDrawView.o cocoaPopUpView.o cocoaCpuView.o FSController.o FSRoundedView.o FSToolbarController.o FSTransparentButton.o ++COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit -framework CoreFoundation -framework OpenGL -framework ApplicationServices + ifdef CONFIG_COREAUDIO + COCOA_LIBS+=-framework CoreAudio + endif +@@ -465,7 +469,11 @@ + $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) + +-cocoa.o: cocoa.m ++ ++cocoa%.o: host-cocoa/cocoa%.m ++ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< ++ ++FS%.o: host-cocoa/FSControls/FS%.m + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + + sdl.o: sdl.c keymaps.c sdl_keysym.h diff --git a/qemu/patches/q_vga.c_02.diff b/qemu/patches/q_vga.c_02.diff new file mode 100644 index 0000000..1eb4e28 --- /dev/null +++ b/qemu/patches/q_vga.c_02.diff @@ -0,0 +1,41 @@ +--- vga.c 2005-12-19 23:51:53.000000000 +0100 ++++ vga2.c 2006-04-10 20:21:56.000000000 +0200 +@@ -788,22 +788,38 @@ + + static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 5) << 5) | ((g >> 5) << 2) | (r >> 6); ++#else + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); ++#endif + } + + static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); ++#else + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); ++#endif + } + + static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); ++#else + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); ++#endif + } + + static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) + { ++#if __LITTLE_ENDIAN__ ++ return (b << 16) | (g << 8) | r; ++#else + return (r << 16) | (g << 8) | b; ++#endif + } + + #define DEPTH 8 diff --git a/qemu/patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch b/qemu/patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch new file mode 100644 index 0000000..8743037 --- /dev/null +++ b/qemu/patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch @@ -0,0 +1,137 @@ +2005-11-11 Gwenole Beauchesne + + * Check for stack clobbers in functions using GOTO_LABEL_PARAM(). + +--- qemu-0.7.2/dyngen.c.dyngen-check-stack-clobbers 2005-11-11 16:26:33.000000000 +0100 ++++ qemu-0.7.2/dyngen.c 2005-11-11 17:30:29.000000000 +0100 +@@ -1414,6 +1414,9 @@ int arm_emit_ldr_info(const char *name, + #define FLAG_TARGET (1 << 3) + /* This is a magic instruction that needs fixing up. */ + #define FLAG_EXIT (1 << 4) ++/* This instruction clobbers the stack pointer. */ ++/* XXX only supports push, pop, add/sub $imm,%esp */ ++#define FLAG_STACK (1 << 5) + #define MAX_EXITS 5 + + static void +@@ -1454,6 +1457,7 @@ trace_i386_insn (const char *name, uint8 + int is_jmp; + int is_exit; + int is_pcrel; ++ int is_stack; + int immed; + int seen_rexw; + int32_t disp; +@@ -1476,6 +1480,7 @@ trace_i386_insn (const char *name, uint8 + is_exit = 0; + seen_rexw = 0; + is_pcrel = 0; ++ is_stack = 0; + + while (is_prefix) { + op = ptr[insn_size]; +@@ -1522,6 +1527,7 @@ trace_i386_insn (const char *name, uint8 + switch (op & 0x7) { + case 0: /* push fs/gs */ + case 1: /* pop fs/gs */ ++ is_stack = 1; + case 2: /* cpuid/rsm */ + modrm = 0; + break; +@@ -1594,6 +1600,7 @@ trace_i386_insn (const char *name, uint8 + #endif + case 5: /* push/pop general register. */ + modrm = 0; ++ is_stack = 1; + break; + + case 6: +@@ -1601,6 +1608,7 @@ trace_i386_insn (const char *name, uint8 + case 0: /* pusha */ + case 1: /* popa */ + modrm = 0; ++ is_stack = 1; + break; + case 2: /* bound */ + case 3: /* arpl */ +@@ -1620,10 +1628,12 @@ trace_i386_insn (const char *name, uint8 + case 8: /* push immediate */ + immed = op_size; + modrm = 0; ++ is_stack = 1; + break; + case 10: /* push 8-bit immediate */ + immed = 1; + modrm = 0; ++ is_stack = 1; + break; + case 9: /* imul immediate */ + immed = op_size; +@@ -1653,8 +1663,22 @@ trace_i386_insn (const char *name, uint8 + immed = op_size; + else + immed = 1; ++ if (op == 0x81 || op == 0x83) { ++ /* add, sub */ ++ op = ptr[insn_size]; ++ switch ((op >> 3) & 7) { ++ case 0: ++ case 5: ++ is_stack = (op & 7) == 4; ++ break; ++ } ++ } + } +- /* else test, xchg, mov, lea or pop general. */ ++ else if ((op & 0xf) == 0xf) { ++ /* pop general. */ ++ is_stack = 1; ++ } ++ /* else test, xchg, mov, lea. */ + break; + + case 9: +@@ -1904,6 +1928,9 @@ trace_i386_insn (const char *name, uint8 + if (is_exit) + flags[insn] |= FLAG_EXIT; + ++ if (is_stack) ++ flags[insn] |= FLAG_STACK; ++ + if (!(is_jmp || is_ret || is_exit)) + flags[insn + insn_size] |= FLAG_INSN; + } +@@ -1924,6 +1951,7 @@ static int trace_i386_op(const char * na + int num_exits; + int len; + int last_insn; ++ int stack_clobbered; + + len = *plen; + flags = malloc(len + 1); +@@ -1947,6 +1975,7 @@ static int trace_i386_op(const char * na + retpos = -1; + num_exits = 0; + last_insn = 0; ++ stack_clobbered = 0; + for (insn = 0; insn < len; insn++) { + if (flags[insn] & FLAG_RET) { + /* ??? In theory it should be possible to handle multiple return +@@ -1956,6 +1985,8 @@ static int trace_i386_op(const char * na + retpos = insn; + } + if (flags[insn] & FLAG_EXIT) { ++ if (stack_clobbered) ++ error("Stack clobbered in %s", name); + if (num_exits == MAX_EXITS) + error("Too many block exits in %s", name); + exit_addrs[num_exits] = insn; +@@ -1963,6 +1994,8 @@ static int trace_i386_op(const char * na + } + if (flags[insn] & FLAG_INSN) + last_insn = insn; ++ if (flags[insn] & FLAG_STACK) ++ stack_clobbered = 1; + } + + exit_addrs[num_exits] = -1; diff --git a/qemu/patches/qemu-0.7.2-gcc4-opts.patch b/qemu/patches/qemu-0.7.2-gcc4-opts.patch new file mode 100644 index 0000000..ce5e3aa --- /dev/null +++ b/qemu/patches/qemu-0.7.2-gcc4-opts.patch @@ -0,0 +1,37 @@ +2005-11-11 Gwenole Beauchesne + + * Globaaly save %ebx, %esi, %edi on entry to generated + function. This avoids some register spills in synthetic opcodes. + NOTE: this also easily fixes gcc4 compiled qemu-system-x86_64 on x86. + +--- qemu-0.7.2/cpu-exec.c.gcc4-opts 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/cpu-exec.c 2005-11-11 17:40:47.000000000 +0100 +@@ -561,6 +561,15 @@ int cpu_exec(CPUState *env1) + : /* no outputs */ + : "r" (gen_func) + : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); ++#elif defined(TARGET_X86_64) && defined(__i386__) ++ asm volatile ("push %%ebx\n" ++ "push %%esi\n" ++ "push %%edi\n" ++ "call *%0\n" ++ "pop %%edi\n" ++ "pop %%esi\n" ++ "pop %%ebx\n" ++ : : "r" (gen_func) : "ebx", "esi", "edi"); + #elif defined(TARGET_I386) && defined(USE_CODE_COPY) + { + if (!(tb->cflags & CF_CODE_COPY)) { +--- qemu-0.7.2/Makefile.target.gcc4-opts 2005-11-11 16:26:33.000000000 +0100 ++++ qemu-0.7.2/Makefile.target 2005-11-11 17:59:56.000000000 +0100 +@@ -65,6 +65,10 @@ OP_CFLAGS+= -falign-functions=0 -fno-gcs + else + OP_CFLAGS+= -malign-functions=0 + endif ++ifeq ($(TARGET_ARCH), x86_64) ++# XXX globally save %ebx, %esi, %edi on entry to generated function ++OP_CFLAGS+= -fcall-used-ebx -fcall-used-esi -fcall-used-edi ++endif + + ifdef TARGET_GPROF + USE_I386_LD=y diff --git a/qemu/patches/qemu-0.8.0-gcc4-hacks.patch b/qemu/patches/qemu-0.8.0-gcc4-hacks.patch new file mode 100644 index 0000000..f7cbdcf --- /dev/null +++ b/qemu/patches/qemu-0.8.0-gcc4-hacks.patch @@ -0,0 +1,118 @@ +2005-10-28 Gwenole Beauchesne + + * Various additional hacks for GCC4. + +--- qemu-0.7.2/target-i386/ops_sse.h.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/target-i386/ops_sse.h 2005-10-28 10:09:21.000000000 +0200 +@@ -34,6 +34,12 @@ + #define Q(n) XMM_Q(n) + #define SUFFIX _xmm + #endif ++#if defined(__i386__) && __GNUC__ >= 4 ++#define RegCopy(d, s) __builtin_memcpy(&(d), &(s), sizeof(d)) ++#endif ++#ifndef RegCopy ++#define RegCopy(d, s) d = s ++#endif + + void OPPROTO glue(op_psrlw, SUFFIX)(void) + { +@@ -570,7 +576,7 @@ void OPPROTO glue(op_pshufw, SUFFIX) (vo + r.W(1) = s->W((order >> 2) & 3); + r.W(2) = s->W((order >> 4) & 3); + r.W(3) = s->W((order >> 6) & 3); +- *d = r; ++ RegCopy(*d, r); + } + #else + void OPPROTO op_shufps(void) +--- qemu-0.7.2/target-i386/helper.c.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/target-i386/helper.c 2005-10-28 10:09:21.000000000 +0200 +@@ -3130,8 +3130,15 @@ void helper_fxrstor(target_ulong ptr, in + nb_xmm_regs = 8 << data64; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { ++#if defined(__i386__) && __GNUC__ >= 4 ++ env->xmm_regs[i].XMM_L(0) = ldl(addr); ++ env->xmm_regs[i].XMM_L(1) = ldl(addr + 4); ++ env->xmm_regs[i].XMM_L(2) = ldl(addr + 8); ++ env->xmm_regs[i].XMM_L(3) = ldl(addr + 12); ++#else + env->xmm_regs[i].XMM_Q(0) = ldq(addr); + env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); ++#endif + addr += 16; + } + } +--- qemu-0.7.2/cpu-all.h.gcc4-hacks 2005-09-04 19:11:31.000000000 +0200 ++++ qemu-0.7.2/cpu-all.h 2005-10-28 10:09:21.000000000 +0200 +@@ -339,7 +339,13 @@ + + static inline void stq_le_p(void *ptr, uint64_t v) + { ++#if defined(__i386__) && __GNUC__ >= 4 ++ const union { uint64_t v; uint32_t p[2]; } x = { .v = v }; ++ ((uint32_t *)ptr)[0] = x.p[0]; ++ ((uint32_t *)ptr)[1] = x.p[1]; ++#else + *(uint64_t *)ptr = v; ++#endif + } + + /* float access */ +--- qemu-0.7.2/softmmu_header.h.gcc4-hacks 2005-10-28 10:08:08.000000000 +0200 ++++ qemu-0.7.2/softmmu_header.h 2005-10-28 10:09:21.000000000 +0200 +@@ -104,7 +104,7 @@ + void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user); + + #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ +- (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) ++ (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) && (__GNUC__ < 4) + + #define CPU_TLB_ENTRY_BITS 4 + +@@ -131,7 +131,7 @@ static inline RES_TYPE glue(glue(ld, USU + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + return res; + } + +@@ -178,13 +178,14 @@ static inline int glue(glue(lds, SUFFIX) + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + return res; + } + #endif + +-static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) ++static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE val) + { ++ RES_TYPE v = val; + asm volatile ("movl %0, %%edx\n" + "movl %0, %%eax\n" + "shrl %3, %%edx\n" +@@ -236,16 +237,14 @@ + "2:\n" + : + : "r" (ptr), +-/* NOTE: 'q' would be needed as constraint, but we could not use it +- with T1 ! */ +- "r" (v), ++ "q" (v), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) +- : "%eax", "%ecx", "%edx", "memory", "cc"); ++ : "%eax", "%edx", "memory", "cc"); + } + + /* TODO: handle 64-bit access sizes and addresses */ diff --git a/qemu/patches/qemu-0.8.0-osx-bugfix.patch b/qemu/patches/qemu-0.8.0-osx-bugfix.patch new file mode 100644 index 0000000..a04c0f5 --- /dev/null +++ b/qemu/patches/qemu-0.8.0-osx-bugfix.patch @@ -0,0 +1,155 @@ +--- qemu-0.8.0/target-i386/helper.c.osx-bugfix 2006-03-17 14:19:42.000000000 +0900 ++++ qemu-0.8.0/target-i386/helper.c 2006-03-17 07:27:57.000000000 +0900 +@@ -28,68 +28,6 @@ do {\ + (raise_exception_err)(a, b);\ + } while (0) + #endif +- +-const uint8_t parity_table[256] = { +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, +- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +-}; +- +-/* modulo 17 table */ +-const uint8_t rclw_table[32] = { +- 0, 1, 2, 3, 4, 5, 6, 7, +- 8, 9,10,11,12,13,14,15, +- 16, 0, 1, 2, 3, 4, 5, 6, +- 7, 8, 9,10,11,12,13,14, +-}; +- +-/* modulo 9 table */ +-const uint8_t rclb_table[32] = { +- 0, 1, 2, 3, 4, 5, 6, 7, +- 8, 0, 1, 2, 3, 4, 5, 6, +- 7, 8, 0, 1, 2, 3, 4, 5, +- 6, 7, 8, 0, 1, 2, 3, 4, +-}; +- +-const CPU86_LDouble f15rk[7] = +-{ +- 0.00000000000000000000L, +- 1.00000000000000000000L, +- 3.14159265358979323851L, /*pi*/ +- 0.30102999566398119523L, /*lg2*/ +- 0.69314718055994530943L, /*ln2*/ +- 1.44269504088896340739L, /*l2e*/ +- 3.32192809488736234781L, /*l2t*/ +-}; + + /* thread support */ + +--- qemu-0.8.0/target-i386/op.c.osx-bugfix 2006-03-17 14:20:37.000000000 +0900 ++++ qemu-0.8.0/target-i386/op.c 2006-03-17 07:28:40.000000000 +0900 +@@ -21,19 +21,69 @@ + #define ASM_SOFTMMU + #include "exec.h" + +-#if defined(__APPLE__) +-/* XXX avoid indirect symbols, correct address patched at code generation time. */ +-static const uint8_t parity_table[256]; +-static const uint8_t rclw_table[32]; +-static const uint8_t rclb_table[32]; +-static const CPU86_LDouble f15rk[7]; +-#else +-extern const uint8_t parity_table[256]; +-extern const uint8_t rclw_table[32]; +-extern const uint8_t rclb_table[32]; +-extern const CPU86_LDouble f15rk[7]; +-#endif ++const uint8_t parity_table[256] = { ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, ++ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, ++}; + ++/* modulo 17 table */ ++const uint8_t rclw_table[32] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 9,10,11,12,13,14,15, ++ 16, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 9,10,11,12,13,14, ++}; ++ ++/* modulo 9 table */ ++const uint8_t rclb_table[32] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 0, 1, 2, 3, 4, ++}; ++ ++const CPU86_LDouble f15rk[7] = ++{ ++ 0.00000000000000000000L, ++ 1.00000000000000000000L, ++ 3.14159265358979323851L, /*pi*/ ++ 0.30102999566398119523L, /*lg2*/ ++ 0.69314718055994530943L, /*ln2*/ ++ 1.44269504088896340739L, /*l2e*/ ++ 3.32192809488736234781L, /*l2t*/ ++}; ++ ++ + /* n must be a constant to be efficient */ + static inline target_long lshift(target_long x, int n) + { diff --git a/qemu/patches/qemu-0.9.0-arm-shift.patch b/qemu/patches/qemu-0.9.0-arm-shift.patch new file mode 100644 index 0000000..810f232 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-arm-shift.patch @@ -0,0 +1,20 @@ +--- qemu-0.9.0/target-arm/op.c 2007-07-23 06:57:25.000000000 +0200 ++++ qemu/target-arm/op.c 2007-07-23 06:58:25.000000000 +0200 +@@ -819,7 +819,7 @@ + int shift; + shift = PARAM1; + if (shift != 0) { +- env->CF = (T1 >> (32 - shift)) & 1; ++ env->CF = (T0 >> (32 - shift)) & 1; + T0 = T0 << shift; + } + env->NZF = T0; +@@ -832,7 +832,7 @@ + + shift = PARAM1; + if (shift == 0) { +- env->CF = ((uint32_t)shift) >> 31; ++ env->CF = ((uint32_t)T0) >> 31; + T0 = 0; + } else { + env->CF = (T0 >> (shift - 1)) & 1; diff --git a/qemu/patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch b/qemu/patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch new file mode 100644 index 0000000..65aaaf1 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch @@ -0,0 +1,19 @@ +2007-02-01 Mike kronenberg + + * Fix for QEMU 0.9.0. + +2006-02-12 Gwenole Beauchesne + + * Enforce 16-byte boundaries. + +--- qemu-0.8.0/Makefile.target.enforce-16byte-stack-boundary 2006-02-12 17:46:54.000000000 +0100 ++++ qemu-0.8.0/Makefile.target 2006-02-12 17:55:24.000000000 +0100 +@@ -67,7 +67,7 @@ endif + + ifeq ($(ARCH),i386) + HELPER_CFLAGS+=-fomit-frame-pointer +-OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer ++OP_CFLAGS+=-fomit-frame-pointer + ifeq ($(HAVE_GCC3_OPTIONS),yes) + OP_CFLAGS+= -falign-functions=0 -fno-gcse + else diff --git a/qemu/patches/qemu-0.9.0-gcc4.patch b/qemu/patches/qemu-0.9.0-gcc4.patch new file mode 100644 index 0000000..5eca38b --- /dev/null +++ b/qemu/patches/qemu-0.9.0-gcc4.patch @@ -0,0 +1,892 @@ +2007-02-01 Mike Kronenberg + + * target-ppc/exec.h: Fix for QEMU 0.9.0. + * dyngen-exec.h: Fix for QEMU 0.9.0. + +2005-06-02 Gwenole Beauchesne + + * dyngen.c (trace_i386_insn): Fix push/imul case with 8-bit + immediate. + +2005-05-11 Paul Brook + + * gcc4 host support. + +--- qemu-0.7.0/target-ppc/exec.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/target-ppc/exec.h 2005-06-02 21:41:51.000000000 +0200 +@@ -33,11 +33,7 @@ #define FT0 (env->ft0) + #define FT1 (env->ft1) + #define FT2 (env->ft2) + +-#if defined (DEBUG_OP) +-# define RETURN() __asm__ __volatile__("nop" : : : "memory"); +-#else +-# define RETURN() __asm__ __volatile__("" : : : "memory"); +-#endif ++#define RETURN() FORCE_RET() + + #include "cpu.h" + #include "exec-all.h" +--- qemu-0.7.0/dyngen-exec.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/dyngen-exec.h 2005-06-02 21:41:51.000000000 +0200 +@@ -155,7 +155,12 @@ extern int printf(const char *, ...); + #endif + + /* force GCC to generate only one epilog at the end of the function */ ++#if defined(__i386__) || defined(__x86_64__) ++/* Also add 4 bytes of padding so that we can replace the ret with a jmp. */ ++#define FORCE_RET() asm volatile ("nop;nop;nop;nop"); ++#else + #define FORCE_RET() __asm__ __volatile__("" : : : "memory"); ++#endif + + #ifndef OPPROTO + #define OPPROTO +@@ -205,12 +210,19 @@ extern int __op_jmp0, __op_jmp1, __op_jm + #endif + + #ifdef __i386__ +-#define EXIT_TB() asm volatile ("ret") +-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) ++/* Dyngen will replace hlt instructions with a ret instruction. Inserting a ++ ret directly would confuse dyngen. */ ++#define EXIT_TB() asm volatile ("hlt") ++/* Dyngen will replace cli with 0x9e (jmp). ++ We generate the offset manually. */ ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif + #ifdef __x86_64__ +-#define EXIT_TB() asm volatile ("ret") +-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) ++/* The same as i386. */ ++#define EXIT_TB() asm volatile ("hlt") ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif + #ifdef __powerpc__ + #define EXIT_TB() asm volatile ("blr") +--- qemu-0.7.0/dyngen.c.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/dyngen.c 2005-06-02 22:25:06.000000000 +0200 +@@ -32,6 +32,8 @@ + + #include "config-host.h" + ++//#define DEBUG_OP ++ + /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross + compilation */ + #if defined(CONFIG_WIN32) +@@ -1343,6 +1345,644 @@ int arm_emit_ldr_info(const char *name, + #endif + + ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ ++/* This byte is the first byte of an instruction. */ ++#define FLAG_INSN (1 << 0) ++/* This byte has been processed as part of an instruction. */ ++#define FLAG_SCANNED (1 << 1) ++/* This instruction is a return instruction. Gcc cometimes generates prefix ++ bytes, so may be more than one byte long. */ ++#define FLAG_RET (1 << 2) ++/* This is either the target of a jump, or the preceeding instruction uses ++ a pc-relative offset. */ ++#define FLAG_TARGET (1 << 3) ++/* This is a magic instruction that needs fixing up. */ ++#define FLAG_EXIT (1 << 4) ++#define MAX_EXITS 5 ++ ++static void ++bad_opcode(const char *name, uint32_t op) ++{ ++ error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name); ++} ++ ++/* Mark len bytes as scanned, Returns insn_size + len. Reports an error ++ if these bytes have already been scanned. */ ++static int ++eat_bytes(const char *name, char *flags, int insn, int insn_size, int len) ++{ ++ while (len > 0) { ++ /* This should never occur in sane code. */ ++ if (flags[insn + insn_size] & FLAG_SCANNED) ++ error ("Overlapping instructions in %s", name); ++ flags[insn + insn_size] |= FLAG_SCANNED; ++ insn_size++; ++ len--; ++ } ++ return insn_size; ++} ++ ++static void ++trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn, ++ int len) ++{ ++ uint8_t *ptr; ++ uint8_t op; ++ int modrm; ++ int is_prefix; ++ int op_size; ++ int addr_size; ++ int insn_size; ++ int is_ret; ++ int is_condjmp; ++ int is_jmp; ++ int is_exit; ++ int is_pcrel; ++ int immed; ++ int seen_rexw; ++ int32_t disp; ++ ++ ptr = start_p + insn; ++ /* nonzero if this insn has a ModR/M byte. */ ++ modrm = 1; ++ /* The size of the immediate value in this instruction. */ ++ immed = 0; ++ /* The operand size. */ ++ op_size = 4; ++ /* The address size */ ++ addr_size = 4; ++ /* The total length of this instruction. */ ++ insn_size = 0; ++ is_prefix = 1; ++ is_ret = 0; ++ is_condjmp = 0; ++ is_jmp = 0; ++ is_exit = 0; ++ seen_rexw = 0; ++ is_pcrel = 0; ++ ++ while (is_prefix) { ++ op = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ is_prefix = 0; ++ switch (op >> 4) { ++ case 0: ++ case 1: ++ case 2: ++ case 3: ++ if (op == 0x0f) { ++ /* two-byte opcode. */ ++ op = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ switch (op >> 4) { ++ case 0: ++ if ((op & 0xf) > 3) ++ modrm = 0; ++ break; ++ case 1: /* vector move or prefetch */ ++ case 2: /* various moves and vector compares. */ ++ case 4: /* cmov */ ++ case 5: /* vector instructions */ ++ case 6: ++ case 13: ++ case 14: ++ case 15: ++ break; ++ case 7: /* mmx */ ++ if (op & 0x77) /* emms */ ++ modrm = 0; ++ break; ++ case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */ ++ modrm = 0; ++ break; ++ case 8: /* long conditional jump */ ++ is_condjmp = 1; ++ immed = op_size; ++ modrm = 0; ++ break; ++ case 9: /* setcc */ ++ break; ++ case 10: ++ switch (op & 0x7) { ++ case 0: /* push fs/gs */ ++ case 1: /* pop fs/gs */ ++ case 2: /* cpuid/rsm */ ++ modrm = 0; ++ break; ++ case 4: /* shld/shrd immediate */ ++ immed = 1; ++ break; ++ default: /* Normal instructions with a ModR/M byte. */ ++ break; ++ } ++ break; ++ case 11: ++ switch (op & 0xf) { ++ case 10: /* bt, bts, btr, btc */ ++ immed = 1; ++ break; ++ default: ++ /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr ++ undefined, and movsx */ ++ break; ++ } ++ break; ++ case 12: ++ if (op & 8) { ++ /* bswap */ ++ modrm = 0; ++ } else { ++ switch (op & 0x7) { ++ case 2: ++ case 4: ++ case 5: ++ case 6: ++ immed = 1; ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ } ++ } else if ((op & 0x07) <= 0x3) { ++ /* General arithmentic ax. */ ++ } else if ((op & 0x07) <= 0x5) { ++ /* General arithmetic ax, immediate. */ ++ if (op & 0x01) ++ immed = op_size; ++ else ++ immed = 1; ++ modrm = 0; ++ } else if ((op & 0x23) == 0x22) { ++ /* Segment prefix. */ ++ is_prefix = 1; ++ } else { ++ /* Segment register push/pop or DAA/AAA/DAS/AAS. */ ++ modrm = 0; ++ } ++ break; ++ ++#if defined(HOST_X86_64) ++ case 4: /* rex prefix. */ ++ is_prefix = 1; ++ /* The address/operand size is actually 64-bit, but the immediate ++ values in the instruction are still 32-bit. */ ++ op_size = 4; ++ addr_size = 4; ++ if (op & 8) ++ seen_rexw = 1; ++ break; ++#else ++ case 4: /* inc/dec register. */ ++#endif ++ case 5: /* push/pop general register. */ ++ modrm = 0; ++ break; ++ ++ case 6: ++ switch (op & 0x0f) { ++ case 0: /* pusha */ ++ case 1: /* popa */ ++ modrm = 0; ++ break; ++ case 2: /* bound */ ++ case 3: /* arpl */ ++ break; ++ case 4: /* FS */ ++ case 5: /* GS */ ++ is_prefix = 1; ++ break; ++ case 6: /* opcode size prefix. */ ++ op_size = 2; ++ is_prefix = 1; ++ break; ++ case 7: /* Address size prefix. */ ++ addr_size = 2; ++ is_prefix = 1; ++ break; ++ case 8: /* push immediate */ ++ immed = op_size; ++ modrm = 0; ++ break; ++ case 10: /* push 8-bit immediate */ ++ immed = 1; ++ modrm = 0; ++ break; ++ case 9: /* imul immediate */ ++ immed = op_size; ++ break; ++ case 11: /* imul 8-bit immediate */ ++ immed = 1; ++ break; ++ case 12: /* insb */ ++ case 13: /* insw */ ++ case 14: /* outsb */ ++ case 15: /* outsw */ ++ modrm = 0; ++ break; ++ } ++ break; ++ ++ case 7: /* Short conditional jump. */ ++ is_condjmp = 1; ++ immed = 1; ++ modrm = 0; ++ break; ++ ++ case 8: ++ if ((op & 0xf) <= 3) { ++ /* arithmetic immediate. */ ++ if ((op & 3) == 1) ++ immed = op_size; ++ else ++ immed = 1; ++ } ++ /* else test, xchg, mov, lea or pop general. */ ++ break; ++ ++ case 9: ++ /* Various single-byte opcodes with no modrm byte. */ ++ modrm = 0; ++ if (op == 10) { ++ /* Call */ ++ immed = 4; ++ } ++ break; ++ ++ case 10: ++ switch ((op & 0xe) >> 1) { ++ case 0: /* mov absoliute immediate. */ ++ case 1: ++ if (seen_rexw) ++ immed = 8; ++ else ++ immed = addr_size; ++ break; ++ case 4: /* test immediate. */ ++ if (op & 1) ++ immed = op_size; ++ else ++ immed = 1; ++ break; ++ default: /* Various string ops. */ ++ break; ++ } ++ modrm = 0; ++ break; ++ ++ case 11: /* move immediate to register */ ++ if (op & 8) { ++ if (seen_rexw) ++ immed = 8; ++ else ++ immed = op_size; ++ } else { ++ immed = 1; ++ } ++ modrm = 0; ++ break; ++ ++ case 12: ++ switch (op & 0xf) { ++ case 0: /* shift immediate */ ++ case 1: ++ immed = 1; ++ break; ++ case 2: /* ret immediate */ ++ immed = 2; ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ case 3: /* ret */ ++ modrm = 0; ++ is_ret = 1; ++ case 4: /* les */ ++ case 5: /* lds */ ++ break; ++ case 6: /* mov immediate byte */ ++ immed = 1; ++ break; ++ case 7: /* mov immediate */ ++ immed = op_size; ++ break; ++ case 8: /* enter */ ++ /* TODO: Is this right? */ ++ immed = 3; ++ modrm = 0; ++ break; ++ case 10: /* retf immediate */ ++ immed = 2; ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ case 13: /* int */ ++ immed = 1; ++ modrm = 0; ++ break; ++ case 11: /* retf */ ++ case 15: /* iret */ ++ modrm = 0; ++ bad_opcode(name, op); ++ break; ++ default: /* leave, int3 or into */ ++ modrm = 0; ++ break; ++ } ++ break; ++ ++ case 13: ++ if ((op & 0xf) >= 8) { ++ /* Coprocessor escape. For our purposes this is just a normal ++ instruction with a ModR/M byte. */ ++ } else if ((op & 0xf) >= 4) { ++ /* AAM, AAD or XLAT */ ++ modrm = 0; ++ } ++ /* else shift instruction */ ++ break; ++ ++ case 14: ++ switch ((op & 0xc) >> 2) { ++ case 0: /* loop or jcxz */ ++ is_condjmp = 1; ++ immed = 1; ++ break; ++ case 1: /* in/out immed */ ++ immed = 1; ++ break; ++ case 2: /* call or jmp */ ++ switch (op & 3) { ++ case 0: /* call */ ++ immed = op_size; ++ break; ++ case 1: /* long jump */ ++ immed = 4; ++ is_jmp = 1; ++ break; ++ case 2: /* far jmp */ ++ bad_opcode(name, op); ++ break; ++ case 3: /* short jmp */ ++ immed = 1; ++ is_jmp = 1; ++ break; ++ } ++ break; ++ case 3: /* in/out register */ ++ break; ++ } ++ modrm = 0; ++ break; ++ ++ case 15: ++ switch ((op & 0xe) >> 1) { ++ case 0: ++ case 1: ++ is_prefix = 1; ++ break; ++ case 2: ++ case 4: ++ case 5: ++ case 6: ++ modrm = 0; ++ /* Some privileged insns are used as markers. */ ++ switch (op) { ++ case 0xf4: /* hlt: Exit translation block. */ ++ is_exit = 1; ++ break; ++ case 0xfa: /* cli: Jump to label. */ ++ is_exit = 1; ++ immed = 4; ++ break; ++ case 0xfb: /* sti: TB patch jump. */ ++ /* Mark the insn for patching, but continue sscanning. */ ++ flags[insn] |= FLAG_EXIT; ++ immed = 4; ++ break; ++ } ++ break; ++ case 3: /* unary grp3 */ ++ if ((ptr[insn_size] & 0x38) == 0) { ++ if (op == 0xf7) ++ immed = op_size; ++ else ++ immed = 1; /* test immediate */ ++ } ++ break; ++ case 7: /* inc/dec grp4/5 */ ++ /* TODO: This includes indirect jumps. We should fail if we ++ encounter one of these. */ ++ break; ++ } ++ break; ++ } ++ } ++ ++ if (modrm) { ++ if (addr_size != 4) ++ error("16-bit addressing mode used in %s", name); ++ ++ disp = 0; ++ modrm = ptr[insn_size]; ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ modrm &= 0xc7; ++ switch ((modrm & 0xc0) >> 6) { ++ case 0: ++ if (modrm == 5) ++ disp = 4; ++ break; ++ case 1: ++ disp = 1; ++ break; ++ case 2: ++ disp = 4; ++ break; ++ } ++ if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) { ++ /* SIB byte */ ++ if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) { ++ disp = 4; ++ is_pcrel = 1; ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, 1); ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, disp); ++ } ++ insn_size = eat_bytes(name, flags, insn, insn_size, immed); ++ if (is_condjmp || is_jmp) { ++ if (immed == 1) { ++ disp = (int8_t)*(ptr + insn_size - 1); ++ } else { ++ disp = (((int32_t)*(ptr + insn_size - 1)) << 24) ++ | (((int32_t)*(ptr + insn_size - 2)) << 16) ++ | (((int32_t)*(ptr + insn_size - 3)) << 8) ++ | *(ptr + insn_size - 4); ++ } ++ disp += insn_size; ++ /* Jumps to external symbols point to the address of the offset ++ before relocation. */ ++ /* ??? These are probably a tailcall. We could fix them up by ++ replacing them with jmp to EOB + call, but it's easier to just ++ prevent the compiler generating them. */ ++ if (disp == 1) ++ error("Unconditional jump (sibcall?) in %s", name); ++ disp += insn; ++ if (disp < 0 || disp > len) ++ error("Jump outside instruction in %s", name); ++ ++ if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED) ++ error("Overlapping instructions in %s", name); ++ ++ flags[disp] |= (FLAG_INSN | FLAG_TARGET); ++ is_pcrel = 1; ++ } ++ if (is_pcrel) { ++ /* Mark the following insn as a jump target. This will stop ++ this instruction being moved. */ ++ flags[insn + insn_size] |= FLAG_TARGET; ++ } ++ if (is_ret) ++ flags[insn] |= FLAG_RET; ++ ++ if (is_exit) ++ flags[insn] |= FLAG_EXIT; ++ ++ if (!(is_jmp || is_ret || is_exit)) ++ flags[insn + insn_size] |= FLAG_INSN; ++} ++ ++/* Scan a function body. Returns the position of the return sequence. ++ Sets *patch_bytes to the number of bytes that need to be copied from that ++ location. If no patching is required (ie. the return is the last insn) ++ *patch_bytes will be set to -1. *plen is the number of code bytes to copy. ++ */ ++static int trace_i386_op(const char * name, uint8_t *start_p, int *plen, ++ int *patch_bytes, int *exit_addrs) ++{ ++ char *flags; ++ int more; ++ int insn; ++ int retpos; ++ int bytes; ++ int num_exits; ++ int len; ++ int last_insn; ++ ++ len = *plen; ++ flags = malloc(len + 1); ++ memset(flags, 0, len + 1); ++ flags[0] |= FLAG_INSN; ++ more = 1; ++ while (more) { ++ more = 0; ++ for (insn = 0; insn < len; insn++) { ++ if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) { ++ trace_i386_insn(name, start_p, flags, insn, len); ++ more = 1; ++ } ++ } ++ } ++ ++ /* Strip any unused code at the end of the function. */ ++ while (len > 0 && flags[len - 1] == 0) ++ len--; ++ ++ retpos = -1; ++ num_exits = 0; ++ last_insn = 0; ++ for (insn = 0; insn < len; insn++) { ++ if (flags[insn] & FLAG_RET) { ++ /* ??? In theory it should be possible to handle multiple return ++ points. In practice it's not worth the effort. */ ++ if (retpos != -1) ++ error("Multiple return instructions in %s", name); ++ retpos = insn; ++ } ++ if (flags[insn] & FLAG_EXIT) { ++ if (num_exits == MAX_EXITS) ++ error("Too many block exits in %s", name); ++ exit_addrs[num_exits] = insn; ++ num_exits++; ++ } ++ if (flags[insn] & FLAG_INSN) ++ last_insn = insn; ++ } ++ ++ exit_addrs[num_exits] = -1; ++ if (retpos == -1) { ++ if (num_exits == 0) { ++ error ("No return instruction found in %s", name); ++ } else { ++ retpos = len; ++ last_insn = len; ++ } ++ } ++ ++ /* If the return instruction is the last instruction we can just ++ remove it. */ ++ if (retpos == last_insn) ++ *patch_bytes = -1; ++ else ++ *patch_bytes = 0; ++ ++ /* Back up over any nop instructions. */ ++ while (retpos > 0 ++ && (flags[retpos] & FLAG_TARGET) == 0 ++ && (flags[retpos - 1] & FLAG_INSN) != 0 ++ && start_p[retpos - 1] == 0x90) { ++ retpos--; ++ } ++ ++ if (*patch_bytes == -1) { ++ *plen = retpos; ++ free (flags); ++ return retpos; ++ } ++ *plen = len; ++ ++ /* The ret is in the middle of the function. Find four more bytes that ++ so the ret can be replaced by a jmp. */ ++ /* ??? Use a short jump where possible. */ ++ bytes = 4; ++ insn = retpos + 1; ++ /* We can clobber everything up to the next jump target. */ ++ while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) { ++ insn++; ++ bytes--; ++ } ++ if (bytes > 0) { ++ /* ???: Strip out nop blocks. */ ++ /* We can't do the replacement without clobbering anything important. ++ Copy preceeding instructions(s) to give us some space. */ ++ while (retpos > 0) { ++ /* If this byte is the target of a jmp we can't move it. */ ++ if (flags[retpos] & FLAG_TARGET) ++ break; ++ ++ (*patch_bytes)++; ++ bytes--; ++ retpos--; ++ ++ /* Break out of the loop if we have enough space and this is either ++ the first byte of an instruction or a pad byte. */ ++ if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED ++ && bytes <= 0) { ++ break; ++ } ++ } ++ } ++ ++ if (bytes > 0) ++ error("Unable to replace ret with jmp in %s\n", name); ++ ++ free(flags); ++ return retpos; ++} ++ ++#endif ++ + #define MAX_ARGS 3 + + /* generate op code */ +@@ -1356,6 +1996,11 @@ void gen_code(const char *name, host_ulo + uint8_t args_present[MAX_ARGS]; + const char *sym_name, *p; + EXE_RELOC *rel; ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ int patch_bytes; ++ int retpos; ++ int exit_addrs[MAX_EXITS]; ++#endif + + /* Compute exact size excluding prologue and epilogue instructions. + * Increment start_offset to skip epilogue instructions, then compute +@@ -1366,33 +2011,12 @@ void gen_code(const char *name, host_ulo + p_end = p_start + size; + start_offset = offset; + #if defined(HOST_I386) || defined(HOST_X86_64) +-#ifdef CONFIG_FORMAT_COFF +- { +- uint8_t *p; +- p = p_end - 1; +- if (p == p_start) +- error("empty code for %s", name); +- while (*p != 0xc3) { +- p--; +- if (p <= p_start) +- error("ret or jmp expected at the end of %s", name); +- } +- copy_size = p - p_start; +- } +-#else + { + int len; + len = p_end - p_start; +- if (len == 0) +- error("empty code for %s", name); +- if (p_end[-1] == 0xc3) { +- len--; +- } else { +- error("ret or jmp expected at the end of %s", name); +- } ++ retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs); + copy_size = len; + } +-#endif + #elif defined(HOST_PPC) + { + uint8_t *p; +@@ -1559,6 +2183,13 @@ void gen_code(const char *name, host_ulo + } + + if (gen_switch == 2) { ++#if defined(HOST_I386) || defined(HOST_X86_64) ++ if (patch_bytes != -1) ++ copy_size += patch_bytes; ++#ifdef DEBUG_OP ++ copy_size += 2; ++#endif ++#endif + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); + } else if (gen_switch == 1) { + +@@ -1761,7 +2392,43 @@ void gen_code(const char *name, host_ulo + #error unsupport object format + #endif + } ++ } ++ /* Replace the marker instructions with the actual opcodes. */ ++ for (i = 0; exit_addrs[i] != -1; i++) { ++ int op; ++ switch (p_start[exit_addrs[i]]) ++ { ++ case 0xf4: op = 0xc3; break; /* hlt -> ret */ ++ case 0xfa: op = 0xe9; break; /* cli -> jmp */ ++ case 0xfb: op = 0xe9; break; /* sti -> jmp */ ++ default: error("Internal error"); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ exit_addrs[i], op); + } ++ /* Fix up the return instruction. */ ++ if (patch_bytes != -1) { ++ if (patch_bytes) { ++ fprintf(outfile, " memcpy(gen_code_ptr + %d," ++ "gen_code_ptr + %d, %d);\n", ++ copy_size, retpos, patch_bytes); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", ++ retpos); ++ fprintf(outfile, ++ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ retpos + 1, copy_size - (retpos + 5)); ++ ++ copy_size += patch_bytes; ++ } ++#ifdef DEBUG_OP ++ fprintf(outfile, ++ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", ++ copy_size); ++ copy_size += 2; ++#endif + } + #elif defined(HOST_X86_64) + { +@@ -1793,6 +2460,42 @@ void gen_code(const char *name, host_ulo + } + } + } ++ /* Replace the marker instructions with the actual opcodes. */ ++ for (i = 0; exit_addrs[i] != -1; i++) { ++ int op; ++ switch (p_start[exit_addrs[i]]) ++ { ++ case 0xf4: op = 0xc3; break; /* hlt -> ret */ ++ case 0xfa: op = 0xe9; break; /* cli -> jmp */ ++ case 0xfb: op = 0xe9; break; /* sti -> jmp */ ++ default: error("Internal error"); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ exit_addrs[i], op); ++ } ++ /* Fix up the return instruction. */ ++ if (patch_bytes != -1) { ++ if (patch_bytes) { ++ fprintf(outfile, " memcpy(gen_code_ptr + %d," ++ "gen_code_ptr + %d, %d);\n", ++ copy_size, retpos, patch_bytes); ++ } ++ fprintf(outfile, ++ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", ++ retpos); ++ fprintf(outfile, ++ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", ++ retpos + 1, copy_size - (retpos + 5)); ++ ++ copy_size += patch_bytes; ++ } ++#ifdef DEBUG_OP ++ fprintf(outfile, ++ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", ++ copy_size); ++ copy_size += 2; ++#endif + } + #elif defined(HOST_PPC) + { +--- qemu-0.7.0/exec-all.h.gcc4 2005-04-27 22:52:05.000000000 +0200 ++++ qemu-0.7.0/exec-all.h 2005-06-02 21:41:51.000000000 +0200 +@@ -335,14 +335,15 @@ do {\ + + #elif defined(__i386__) && defined(USE_DIRECT_JUMP) + +-/* we patch the jump instruction directly */ ++/* we patch the jump instruction directly. Use sti in place of the actual ++ jmp instruction so that dyngen can patch in the correct result. */ + #define GOTO_TB(opname, tbparam, n)\ + do {\ + asm volatile (".section .data\n"\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ + ".long 1f\n"\ + ASM_PREVIOUS_SECTION \ +- "jmp " ASM_NAME(__op_jmp) #n "\n"\ ++ "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\ + "1:\n");\ + } while (0) + diff --git a/qemu/patches/qemu-0.9.0-i386-FORCE_RET.patch b/qemu/patches/qemu-0.9.0-i386-FORCE_RET.patch new file mode 100644 index 0000000..820399d --- /dev/null +++ b/qemu/patches/qemu-0.9.0-i386-FORCE_RET.patch @@ -0,0 +1,26 @@ +2007-02-01 Mike Kronenberg + + * Fix for QEMU 0.9.0. + +2006-06-12 Gwenole Beauchesne + + * Try to enforce one exit point per synthetic opcode (gcc4). + +--- qemu-0.8.0/target-i386/op.c.i386-FORCE_RET 2005-12-19 23:51:53.000000000 +0100 ++++ qemu-0.8.0/target-i386/op.c 2006-02-12 17:51:40.000000000 +0100 +@@ -1032,6 +1032,7 @@ void OPPROTO op_aaa(void) + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; ++ FORCE_RET(); + } + + void OPPROTO op_aas(void) +@@ -1056,6 +1057,7 @@ void OPPROTO op_aas(void) + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; ++ FORCE_RET(); + } + + /* segment handling */ diff --git a/qemu/patches/qemu-0.9.0-osx-intel-port.patch b/qemu/patches/qemu-0.9.0-osx-intel-port.patch new file mode 100644 index 0000000..348b823 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-osx-intel-port.patch @@ -0,0 +1,329 @@ +2007-02-01 Mike Kronenberg + + * Fix for QEMU 0.9.0. + +2006-02-12 Gwenole Beauchesne + + * Port to MacOS X for Intel. + +TODO: + - try test-i386 + - use 80-bit long double? + +--- qemu-0.8.0/target-i386/exec.h.osx-intel-port 2005-12-19 23:51:53.000000000 +0100 ++++ qemu-0.8.0/target-i386/exec.h 2006-02-13 07:20:25.000000000 +0100 +@@ -457,8 +457,6 @@ static inline void helper_fstt(CPU86_LDo + + #define FPUC_EM 0x3f + +-extern const CPU86_LDouble f15rk[7]; +- + void helper_fldt_ST0_A0(void); + void helper_fstt_ST0_A0(void); + void fpu_raise_exception(void); +@@ -492,10 +490,6 @@ float approx_rsqrt(float a); + float approx_rcp(float a); + void update_fp_status(void); + +-extern const uint8_t parity_table[256]; +-extern const uint8_t rclw_table[32]; +-extern const uint8_t rclb_table[32]; +- + static inline uint32_t compute_eflags(void) + { + return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); +--- qemu-0.8.0/target-i386/op.c.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/target-i386/op.c 2006-02-13 07:20:25.000000000 +0100 +@@ -21,6 +21,19 @@ + #define ASM_SOFTMMU + #include "exec.h" + ++#if defined(__APPLE__) ++/* XXX avoid indirect symbols, correct address patched at code generation time. */ ++static const uint8_t parity_table[256]; ++static const uint8_t rclw_table[32]; ++static const uint8_t rclb_table[32]; ++static const CPU86_LDouble f15rk[7]; ++#else ++extern const uint8_t parity_table[256]; ++extern const uint8_t rclw_table[32]; ++extern const uint8_t rclb_table[32]; ++extern const CPU86_LDouble f15rk[7]; ++#endif ++ + /* n must be a constant to be efficient */ + static inline target_long lshift(target_long x, int n) + { +--- qemu-0.8.0/Makefile.target.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/Makefile.target 2006-02-13 01:25:58.000000000 +0100 +@@ -18,6 +18,9 @@ CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) + endif + BASE_CFLAGS= + BASE_LDFLAGS= ++ifeq ($(CONFIG_DARWIN),yes) ++CFLAGS+=-mdynamic-no-pic ++endif + #CFLAGS+=-Werror + LDFLAGS=-g + LIBS= +--- qemu-0.8.0/dyngen.c.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/dyngen.c 2006-02-13 01:25:58.000000000 +0100 +@@ -183,6 +183,20 @@ typedef struct coff_rel { + #include + #include + ++#ifdef HOST_PPC ++ ++#define MACH_CPU_TYPE CPU_TYPE_POWERPC ++#define mach_check_cputype(x) ((x) == CPU_TYPE_POWERPC) ++ ++#elif defined(HOST_I386) ++ ++#define MACH_CPU_TYPE CPU_TYPE_I386 ++#define mach_check_cputype(x) ((x) == CPU_TYPE_I386) ++ ++#else ++#error unsupported CPU - please update the code ++#endif ++ + # define check_mach_header(x) (x.magic == MH_MAGIC) + typedef int32_t host_long; + typedef uint32_t host_ulong; +@@ -981,22 +995,23 @@ static const char * find_reloc_name_in_s + { + unsigned int tocindex, symindex, size; + const char *name = 0; ++ int section_type; + + /* Sanity check */ + if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) ) + return (char*)0; +- +- if( sec_hdr->flags & S_SYMBOL_STUBS ){ ++ ++ section_type = sec_hdr->flags & SECTION_TYPE; ++ if( section_type == S_SYMBOL_STUBS ){ + size = sec_hdr->reserved2; + if(size == 0) + error("size = 0"); +- + } +- else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS || +- sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS) ++ else if( section_type == S_LAZY_SYMBOL_POINTERS || ++ section_type == S_NON_LAZY_SYMBOL_POINTERS) + size = sizeof(unsigned long); + else +- return 0; ++ return NULL; + + /* Compute our index in toc */ + tocindex = (address - sec_hdr->addr)/size; +@@ -1030,8 +1045,27 @@ static const char * get_reloc_name(EXE_R + /* init the slide value */ + *sslide = 0; + +- if(R_SCATTERED & rel->r_address) +- return (char *)find_reloc_name_given_its_address(sca_rel->r_value); ++ if (R_SCATTERED & rel->r_address) { ++ char *name = (char *)find_reloc_name_given_its_address(sca_rel->r_value); ++ ++ /* search it in the full symbol list, if not found */ ++ if (!name) { ++ int i; ++ for (i = 0; i < nb_syms; i++) { ++ EXE_SYM *sym = &symtab[i]; ++ if (sym->st_value == sca_rel->r_value) { ++ name = get_sym_name(sym); ++ switch (sca_rel->r_type) { ++ case GENERIC_RELOC_VANILLA: ++ *sslide = *(uint32_t *)(text + sca_rel->r_address) - sca_rel->r_value; ++ break; ++ } ++ break; ++ } ++ } ++ } ++ return name; ++ } + + if(rel->r_extern) + { +@@ -1063,14 +1097,21 @@ static const char * get_reloc_name(EXE_R + sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc ); + if (sectoffset & 0x02000000) sectoffset |= 0xfc000000; + break; ++ case GENERIC_RELOC_VANILLA: ++ sectoffset = *(uint32_t *)(text + rel->r_address); ++ break; + default: +- error("switch(rel->type) not found"); ++ error("switch(rel->type=%d) not found", rel->r_type); + } + +- if(rel->r_pcrel) ++ if(rel->r_pcrel) { + sectoffset += rel->r_address; +- +- if (rel->r_type == PPC_RELOC_BR24) ++#ifdef HOST_I386 ++ sectoffset += (1 << rel->r_length); ++#endif ++ } ++ ++ if (rel->r_type == PPC_RELOC_BR24 || rel->r_pcrel) + name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, §ion_hdr[sectnum-1]); + + /* search it in the full symbol list, if not found */ +@@ -1122,7 +1163,7 @@ int load_object(const char *filename) + error("bad Mach header"); + } + +- if (mach_hdr.cputype != CPU_TYPE_POWERPC) ++ if (!mach_check_cputype(mach_hdr.cputype)) + error("Unsupported CPU"); + + if (mach_hdr.filetype != MH_OBJECT) +@@ -2413,6 +2454,82 @@ void gen_code(const char *name, host_ulo + /* patch relocations */ + #if defined(HOST_I386) + { ++#ifdef CONFIG_FORMAT_MACH ++ struct scattered_relocation_info *scarel; ++ struct relocation_info * rel; ++ char final_sym_name[256]; ++ const char *sym_name; ++ const char *p; ++ int slide, sslide; ++ int i; ++ ++ for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { ++ unsigned int offset, length, value = 0; ++ unsigned int type, pcrel, isym = 0; ++ unsigned int usesym = 0; ++ ++ if (R_SCATTERED & rel->r_address) { ++ scarel = (struct scattered_relocation_info*)rel; ++ offset = (unsigned int)scarel->r_address; ++ length = scarel->r_length; ++ pcrel = scarel->r_pcrel; ++ type = scarel->r_type; ++ value = scarel->r_value; ++ } ++ else { ++ value = isym = rel->r_symbolnum; ++ usesym = (rel->r_extern); ++ offset = rel->r_address; ++ length = rel->r_length; ++ pcrel = rel->r_pcrel; ++ type = rel->r_type; ++ } ++ ++ slide = offset - start_offset; ++ ++ if (!(offset >= start_offset && offset < start_offset + size)) ++ continue; /* not in our range */ ++ ++ sym_name = get_reloc_name(rel, &sslide); ++ ++ if (usesym && symtab[isym].n_type & N_STAB) ++ continue; /* don't handle STAB (debug sym) */ ++ ++ if (sym_name && strstart(sym_name, "__op_jmp", &p)) { ++ int n; ++ n = strtol(p, NULL, 10); ++ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, slide); ++ continue; /* Nothing more to do */ ++ } ++ ++ if (!sym_name) { ++ fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n", ++ name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type); ++ continue; /* dunno how to handle without final_sym_name */ ++ } ++ ++ get_reloc_expr(final_sym_name, sizeof(final_sym_name), ++ sym_name); ++ ++ if (length != 2) ++ error("unsupported %d-bit relocation", 8 * (1 << length)); ++ ++ switch (type) { ++ case GENERIC_RELOC_VANILLA: ++ if (pcrel || strstart(sym_name,"__op_gen_label",&p)) { ++ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) - 4;\n", ++ slide, final_sym_name, slide); ++ } ++ else { ++ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (%s + %d);\n", ++ slide, final_sym_name, sslide); ++ } ++ break; ++ default: ++ error("unsupported i386 relocation (%d)", type); ++ } ++ } ++#else + char name[256]; + int type; + int addend; +@@ -2482,6 +2599,7 @@ void gen_code(const char *name, host_ulo + #endif + } + } ++#endif + /* Replace the marker instructions with the actual opcodes. */ + for (i = 0; exit_addrs[i] != -1; i++) { + int op; +--- qemu-0.8.0/dyngen-exec.h.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/dyngen-exec.h 2006-02-13 01:25:58.000000000 +0100 +@@ -215,9 +215,16 @@ extern int __op_jmp0, __op_jmp1, __op_jm + #define EXIT_TB() asm volatile ("hlt") + /* Dyngen will replace cli with 0x9e (jmp). + We generate the offset manually. */ ++#if defined(__APPLE__) ++/* XXX Different relocations are generated for MacOS X for Intel ++ (please as from cctools). */ ++#define GOTO_LABEL_PARAM(n) \ ++ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n) ++#else + #define GOTO_LABEL_PARAM(n) \ + asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") + #endif ++#endif + #ifdef __x86_64__ + /* The same as i386. */ + #define EXIT_TB() asm volatile ("hlt") +--- qemu-0.8.0/exec-all.h.osx-intel-port 2006-02-13 01:25:58.000000000 +0100 ++++ qemu-0.8.0/exec-all.h 2006-02-13 01:25:58.000000000 +0100 +@@ -321,15 +321,29 @@ do {\ + + /* we patch the jump instruction directly. Use sti in place of the actual + jmp instruction so that dyngen can patch in the correct result. */ ++#if defined(__APPLE__) ++/* XXX Different relocations are generated for MacOS X for Intel ++ (please as from cctools). */ + #define GOTO_TB(opname, tbparam, n)\ + do {\ +- asm volatile (".section .data\n"\ ++ asm volatile (ASM_DATA_SECTION\ ++ ASM_OP_LABEL_NAME(n, opname) ":\n"\ ++ ".long 1f\n"\ ++ ASM_PREVIOUS_SECTION \ ++ "sti;.long " ASM_NAME(__op_jmp) #n "\n"\ ++ "1:\n");\ ++} while (0) ++#else ++#define GOTO_TB(opname, tbparam, n)\ ++do {\ ++ asm volatile (ASM_DATA_SECTION\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ + ".long 1f\n"\ + ASM_PREVIOUS_SECTION \ + "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\ + "1:\n");\ + } while (0) ++#endif + + #else + diff --git a/qemu/patches/qemu-0.9.0-qcow2.diff b/qemu/patches/qemu-0.9.0-qcow2.diff new file mode 100644 index 0000000..89a499c --- /dev/null +++ b/qemu/patches/qemu-0.9.0-qcow2.diff @@ -0,0 +1,26 @@ +--- block-qcow2.c 2006/08/07 02:38:06 1.4 ++++ block-qcow2.c 2007/04/02 12:48:47 1.6 +@@ -1886,6 +1886,8 @@ + int64_t table_offset; + uint64_t data64; + uint32_t data32; ++ int old_table_size; ++ int64_t old_table_offset; + + if (min_size <= s->refcount_table_size) + return 0; +@@ -1931,10 +1933,14 @@ + &data32, sizeof(data32)) != sizeof(data32)) + goto fail; + qemu_free(s->refcount_table); ++ old_table_offset = s->refcount_table_offset; ++ old_table_size = s->refcount_table_size; + s->refcount_table = new_table; + s->refcount_table_size = new_table_size; ++ s->refcount_table_offset = table_offset; + + update_refcount(bs, table_offset, new_table_size2, 1); ++ free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); + return 0; + fail: + free_clusters(bs, table_offset, new_table_size2); diff --git a/qemu/patches/qemu-0.9.0-sparc-clobber.patch b/qemu/patches/qemu-0.9.0-sparc-clobber.patch new file mode 100644 index 0000000..dc6c792 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-sparc-clobber.patch @@ -0,0 +1,10 @@ +--- qemu-0.9.0/cpu-exec.c 2007-07-22 18:05:41.000000000 +0200 ++++ qemu/cpu-exec.c 2007-07-22 18:04:24.000000000 +0200 +@@ -645,6 +645,7 @@ + : /* no outputs */ + : "r" (gen_func) + : "i0", "i1", "i2", "i3", "i4", "i5", ++ "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5", + "l6", "l7"); + #elif defined(__arm__) diff --git a/qemu/patches/qemu-0.9.0-sparc-compile-flags.patch b/qemu/patches/qemu-0.9.0-sparc-compile-flags.patch new file mode 100644 index 0000000..8d09aac --- /dev/null +++ b/qemu/patches/qemu-0.9.0-sparc-compile-flags.patch @@ -0,0 +1,23 @@ +diff -ur qemu/Makefile.target qemu-ecd/Makefile.target +--- qemu/Makefile.target 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/Makefile.target 2007-07-22 19:33:00.000000000 +0200 +@@ -122,14 +122,14 @@ + + ifeq ($(ARCH),sparc) + ifeq ($(CONFIG_SOLARIS),yes) +-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 ++BASE_CFLAGS+=-mcpu=ultrasparc -m32 -U__sparc_v9__ + BASE_LDFLAGS+=-m32 +-OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 ++OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -Wa,-Av9a + else +-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 ++BASE_CFLAGS+=-mcpu=ultrasparc -m32 -U__sparc_v9__ + BASE_LDFLAGS+=-m32 +-OP_CFLAGS+=-fno-delayed-branch -ffixed-i0 +-HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat ++OP_CFLAGS+=-fno-delayed-branch -Wa,-Av9a ++HELPER_CFLAGS=$(CFLAGS) + # -static is used to avoid g1/g3 usage by the dynamic linker + BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static + endif diff --git a/qemu/patches/qemu-0.9.0-sparc-load-store-le.patch b/qemu/patches/qemu-0.9.0-sparc-load-store-le.patch new file mode 100644 index 0000000..7ec7453 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-sparc-load-store-le.patch @@ -0,0 +1,67 @@ +diff -ur qemu/cpu-all.h qemu-0.9.0/cpu-all.h +--- qemu/cpu-all.h 2007-07-21 11:53:24.000000000 +0200 ++++ qemu-0.9.0/cpu-all.h 2007-07-04 09:48:06.000000000 +0200 +@@ -24,6 +24,12 @@ + #define WORDS_ALIGNED + #endif + ++#if defined(__sparc__) ++#ifndef ASI_PL ++#define ASI_PL 0x88 ++#endif ++#endif ++ + /* some important defines: + * + * WORDS_ALIGNED : if defined, the host cpu can only make word aligned +@@ -197,6 +203,10 @@ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; ++#elif defined(__sparc__) ++ uint16_t val; ++ __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return p[0] | (p[1] << 8); +@@ -209,6 +219,10 @@ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; ++#elif defined(__sparc__) ++ int16_t val; ++ __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +@@ -221,6 +235,10 @@ + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; ++#elif defined(__sparc__) ++ uint32_t val; ++ __asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (val) : "r" (ptr), "i" (ASI_PL)); ++ return val; + #else + uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +@@ -240,6 +258,8 @@ + { + #ifdef __powerpc__ + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); ++#elif defined(__sparc__) ++ __asm__ __volatile__ ("stha %0, [%1] %2" : : "r" (v), "r" (ptr), "i" (ASI_PL)); + #else + uint8_t *p = ptr; + p[0] = v; +@@ -251,6 +271,8 @@ + { + #ifdef __powerpc__ + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); ++#elif defined(__sparc__) ++ __asm__ __volatile__ ("stwa %0, [%1] %2" : : "r" (v), "r" (ptr), "i" (ASI_PL)); + #else + uint8_t *p = ptr; + p[0] = v; diff --git a/qemu/patches/qemu-0.9.0-sparc-register.patch b/qemu/patches/qemu-0.9.0-sparc-register.patch new file mode 100644 index 0000000..59a7e1f --- /dev/null +++ b/qemu/patches/qemu-0.9.0-sparc-register.patch @@ -0,0 +1,173 @@ +diff -ur qemu/cpu-exec.c qemu-ecd/cpu-exec.c +--- qemu/cpu-exec.c 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/cpu-exec.c 2007-07-22 19:26:22.000000000 +0200 +@@ -233,10 +233,6 @@ + uint32_t *saved_regwptr; + #endif + #endif +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- int saved_i7; +- target_ulong tmp_T0; +-#endif + int ret, interrupt_request; + void (*gen_func)(void); + TranslationBlock *tb; +@@ -300,10 +296,6 @@ + #define SAVE_HOST_REGS 1 + #include "hostregs_helper.h" + env = env1; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- /* we also save i7 because longjmp may not restore it */ +- asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); +-#endif + + #if defined(TARGET_I386) + env_to_regs(); +@@ -403,10 +395,6 @@ + + T0 = 0; /* force lookup of first TB */ + for(;;) { +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- /* g1 can be modified by some libc? functions */ +- tmp_T0 = T0; +-#endif + interrupt_request = env->interrupt_request; + if (__builtin_expect(interrupt_request, 0)) { + #if defined(TARGET_I386) +@@ -414,11 +402,7 @@ + !(env->hflags & HF_SMM_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { +@@ -431,11 +415,7 @@ + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + #elif defined(TARGET_PPC) + #if 0 +@@ -450,22 +430,14 @@ + env->error_code = 0; + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { + /* Raise it */ + env->exception_index = EXCP_DECR; + env->error_code = 0; + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + } + #elif defined(TARGET_MIPS) +@@ -479,11 +451,7 @@ + env->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + do_interrupt(env); +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + #elif defined(TARGET_SPARC) + if ((interrupt_request & CPU_INTERRUPT_HARD) && +@@ -497,11 +465,7 @@ + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + do_interrupt(env->interrupt_index); + env->interrupt_index = 0; +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + } else if (interrupt_request & CPU_INTERRUPT_TIMER) { + //do_interrupt(0, 0, 0, 0, 0); +@@ -532,11 +496,7 @@ + env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + /* ensure that no TB jump will be modified as + the program flow was changed */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- tmp_T0 = 0; +-#else + T0 = 0; +-#endif + } + if (interrupt_request & CPU_INTERRUPT_EXIT) { + env->interrupt_request &= ~CPU_INTERRUPT_EXIT; +@@ -606,9 +566,6 @@ + lookup_symbol(tb->pc)); + } + #endif +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- T0 = tmp_T0; +-#endif + /* see if we can patch the calling TB. When the TB + spans two pages, we cannot safely do a direct + jump. */ +@@ -800,9 +757,6 @@ + #endif + + /* restore global registers */ +-#if defined(__sparc__) && !defined(HOST_SOLARIS) +- asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); +-#endif + #include "hostregs_helper.h" + + /* fail safe : never use cpu_single_env outside cpu_exec() */ +diff -ur qemu/dyngen-exec.h qemu-ecd/dyngen-exec.h +--- qemu/dyngen-exec.h 2007-07-22 19:35:11.000000000 +0200 ++++ qemu-ecd/dyngen-exec.h 2007-07-22 19:26:22.000000000 +0200 +@@ -142,19 +142,6 @@ + #define AREG1 "g4" + #define AREG2 "g5" + #define AREG3 "g7" +-#else +-#define AREG0 "g6" +-#define AREG1 "g1" +-#define AREG2 "g2" +-#define AREG3 "g3" +-#define AREG4 "l0" +-#define AREG5 "l1" +-#define AREG6 "l2" +-#define AREG7 "l3" +-#define AREG8 "l4" +-#define AREG9 "l5" +-#define AREG10 "l6" +-#define AREG11 "l7" + #endif + #endif + #define USE_FP_CONVERT +diff -ur qemu/target-arm/exec.h qemu-ecd/target-arm/exec.h +--- qemu/target-arm/exec.h 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-ecd/target-arm/exec.h 2007-07-22 19:30:15.000000000 +0200 +@@ -17,6 +17,7 @@ + * 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 "dyngen-exec.h" + + #if defined(__sparc__) diff --git a/qemu/patches/qemu-0.9.0-x49gp-arm-dump-state.patch b/qemu/patches/qemu-0.9.0-x49gp-arm-dump-state.patch new file mode 100644 index 0000000..11febb0 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-arm-dump-state.patch @@ -0,0 +1,37 @@ +diff -ur qemu/target-arm/translate.c qemu-0.9.0/target-arm/translate.c +--- qemu/target-arm/translate.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/target-arm/translate.c 2007-07-10 09:15:56.000000000 +0200 +@@ -2536,7 +2536,9 @@ + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) + { ++ uint32_t psr; + int i; ++#ifndef X49GP + union { + uint32_t i; + float s; +@@ -2548,7 +2550,7 @@ + float64 f64; + double d; + } d0; +- uint32_t psr; ++#endif + + for(i=0;i<16;i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); +@@ -2567,6 +2567,7 @@ + psr & CPSR_T ? 'T' : 'A', + cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); + ++#ifndef X49GP + for (i = 0; i < 16; i++) { + d.d = env->vfp.regs[i]; + s0.i = d.l.lower; +@@ -2579,5 +2580,6 @@ + d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); ++#endif + } + diff --git a/qemu/patches/qemu-0.9.0-x49gp-arm-mmu.patch b/qemu/patches/qemu-0.9.0-x49gp-arm-mmu.patch new file mode 100644 index 0000000..0a54ae1 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-arm-mmu.patch @@ -0,0 +1,192 @@ +diff -ur qemu-0.9.0/target-arm/helper.c qemu/target-arm/helper.c +--- qemu-0.9.0/target-arm/helper.c 2007-07-30 16:48:18.000000000 +0200 ++++ qemu/target-arm/helper.c 2007-07-30 16:46:50.000000000 +0200 +@@ -278,87 +280,101 @@ + static int get_phys_addr(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) + { +- int code; +- uint32_t table; +- uint32_t desc; +- int type; +- int ap; +- int domain; +- uint32_t phys_addr; ++ int code; ++ uint32_t pgdp, ptep; ++ uint32_t pgd, pte = 0; ++ uint32_t index; ++ int ap = 0; ++ int domain = 0; ++ uint32_t phys_addr = 0; ++ ++ /* Fast Context Switch Extension. */ ++ if (address < 0x02000000) ++ address += env->cp15.c13_fcse; ++ ++ if ((env->cp15.c1_sys & 1) == 0) { ++ /* MMU disabled. */ ++ *phys_ptr = address; ++ *prot = PAGE_READ | PAGE_WRITE; ++ return 0; ++ } ++ ++ /* Pagetable walk. */ ++ ++ /* Lookup l1 descriptor. */ ++ pgdp = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); ++ ++ pgd = ldl_phys(pgdp); ++ ++ switch (pgd & 3) { ++ case 0: /* Section translation fault. */ ++ code = 5; ++ goto do_fault; ++ ++ case 1: /* Coarse page table. */ ++ index = (address >> 10) & 0x3fc; ++ ptep = (pgd & 0xfffffc00) | index; ++ ++ pte = ldl_phys(ptep); ++ break; ++ ++ case 2: /* Section. */ ++ phys_addr = (pgd & 0xfff00000) | (address & 0x000fffff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pgd >> 10) & 0x03; ++ code = 13; ++ ++ goto do_check; ++ ++ case 3: /* Fine page table. */ ++ index = (address >> 8) & 0xffc; ++ ptep = (pgd & 0xfffff000) | index; ++ ++ pte = ldl_phys(ptep); ++ break; ++ } ++ ++ code = 15; ++ switch (pte & 3) { ++ case 0: /* Page translation fault. */ ++ code = 7; ++ goto do_fault; ++ ++ case 1: /* Large page. */ ++ phys_addr = (pte & 0xffff0000) | (address & 0x0000ffff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> (4 + ((address >> 13) & 6))) & 3; ++ break; ++ ++ case 2: /* Small page. */ ++ phys_addr = (pte & 0xfffff000) | (address & 0x00000fff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> (4 + ((address >> 13) & 6))) & 3; ++ break; ++ ++ case 3: /* Tiny page. */ ++ phys_addr = (pte & 0xfffffc00) | (address & 0x000003ff); ++ ++ domain = (pgd >> 5) & 0x0f; ++ ap = (pte >> 4) & 3; ++ break; ++ } ++ ++do_check: ++ *prot = check_ap(env, ap, domain, access_type, is_user); ++ if (!*prot) { ++ /* Access permission fault. */ ++ goto do_fault; ++ } + +- /* Fast Context Switch Extension. */ +- if (address < 0x02000000) +- address += env->cp15.c13_fcse; +- +- if ((env->cp15.c1_sys & 1) == 0) { +- /* MMU diusabled. */ +- *phys_ptr = address; +- *prot = PAGE_READ | PAGE_WRITE; +- } else { +- /* Pagetable walk. */ +- /* Lookup l1 descriptor. */ +- table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); +- desc = ldl_phys(table); +- type = (desc & 3); +- domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; +- if (type == 0) { +- /* Secton translation fault. */ +- code = 5; +- goto do_fault; +- } +- if (domain == 0 || domain == 2) { +- if (type == 2) +- code = 9; /* Section domain fault. */ +- else +- code = 11; /* Page domain fault. */ +- goto do_fault; +- } +- if (type == 2) { +- /* 1Mb section. */ +- phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); +- ap = (desc >> 10) & 3; +- code = 13; +- } else { +- /* Lookup l2 entry. */ +- table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); +- desc = ldl_phys(table); +- switch (desc & 3) { +- case 0: /* Page translation fault. */ +- code = 7; +- goto do_fault; +- case 1: /* 64k page. */ +- phys_addr = (desc & 0xffff0000) | (address & 0xffff); +- ap = (desc >> (4 + ((address >> 13) & 6))) & 3; +- break; +- case 2: /* 4k page. */ +- phys_addr = (desc & 0xfffff000) | (address & 0xfff); +- ap = (desc >> (4 + ((address >> 13) & 6))) & 3; +- break; +- case 3: /* 1k page. */ +- if (type == 1) { +- /* Page translation fault. */ +- code = 7; +- goto do_fault; +- } +- phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); +- ap = (desc >> 4) & 3; +- break; +- default: +- /* Never happens, but compiler isn't smart enough to tell. */ +- abort(); +- } +- code = 15; +- } +- *prot = check_ap(env, ap, domain, access_type, is_user); +- if (!*prot) { +- /* Access permission fault. */ +- goto do_fault; +- } + *phys_ptr = phys_addr; +- } +- return 0; ++ return 0; ++ + do_fault: +- return code | (domain << 4); ++ return code | (domain << 4); + } + + int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, +@@ -532,7 +548,7 @@ + return; + bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ +- cpu_abort(env, "Unimplemented cp15 register read\n"); ++ cpu_abort(env, "Unimplemented cp15 register write\n"); + } + + uint32_t helper_get_cp15(CPUState *env, uint32_t insn) diff --git a/qemu/patches/qemu-0.9.0-x49gp-arm-semihosting.patch b/qemu/patches/qemu-0.9.0-x49gp-arm-semihosting.patch new file mode 100644 index 0000000..f343239 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-arm-semihosting.patch @@ -0,0 +1,50 @@ +diff -ur qemu/arm-semi.c qemu-0.9.0/arm-semi.c +--- qemu/arm-semi.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/arm-semi.c 2007-07-03 21:52:52.000000000 +0200 +@@ -196,7 +196,7 @@ + + #define ARG(n) tget32(args + (n) * 4) + #define SET_ARG(n, val) tput32(args + (n) * 4,val) +-uint32_t do_arm_semihosting(CPUState *env) ++int do_arm_semihosting(CPUState *env, uint32_t mask) + { + target_ulong args; + char * s; +diff -ur qemu/linux-user/arm/syscall.h qemu-0.9.0/linux-user/arm/syscall.h +--- qemu/linux-user/arm/syscall.h 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/linux-user/arm/syscall.h 2007-07-03 21:54:32.000000000 +0200 +@@ -39,4 +39,4 @@ + #define UNAME_MACHINE "armv5tel" + #endif + +-uint32_t do_arm_semihosting(CPUState *); ++int do_arm_semihosting(CPUState *, uint32_t); +diff -ur qemu/target-arm/helper.c qemu-0.9.0/target-arm/helper.c +--- qemu/target-arm/helper.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/target-arm/helper.c 2007-07-21 11:44:15.000000000 +0200 +@@ -5,6 +5,8 @@ + #include "cpu.h" + #include "exec-all.h" + ++extern int do_arm_semihosting(CPUARMState *env, uint32_t mask); ++ + void cpu_reset(CPUARMState *env) + { + #if defined (CONFIG_USER_ONLY) +@@ -184,14 +184,8 @@ + } else { + mask = ldl_code(env->regs[15] - 4) & 0xffffff; + } +- /* Only intercept calls from privileged modes, to provide some +- semblance of security. */ +- if (((mask == 0x123456 && !env->thumb) +- || (mask == 0xab && env->thumb)) +- && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { +- env->regs[0] = do_arm_semihosting(env); +- return; +- } ++ if (do_arm_semihosting(env, mask)) ++ return; + } + new_mode = ARM_CPU_MODE_SVC; + addr = 0x08; diff --git a/qemu/patches/qemu-0.9.0-x49gp-block.patch b/qemu/patches/qemu-0.9.0-x49gp-block.patch new file mode 100644 index 0000000..9f579b6 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-block.patch @@ -0,0 +1,1302 @@ +diff -ur qemu-0.9.0/block-qcow.c qemu/block-qcow.c +--- qemu-0.9.0/block-qcow.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-qcow.c 2007-07-30 14:30:18.000000000 +0200 +@@ -69,10 +69,12 @@ + uint8_t *cluster_cache; + uint8_t *cluster_data; + uint64_t cluster_cache_offset; ++#ifndef X49GP + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ + uint32_t crypt_method_header; + AES_KEY aes_encrypt_key; + AES_KEY aes_decrypt_key; ++#endif + } BDRVQcowState; + + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); +@@ -115,9 +117,11 @@ + goto fail; + if (header.crypt_method > QCOW_CRYPT_AES) + goto fail; ++#ifndef X49GP + s->crypt_method_header = header.crypt_method; + if (s->crypt_method_header) + bs->encrypted = 1; ++#endif + s->cluster_bits = header.cluster_bits; + s->cluster_size = 1 << s->cluster_bits; + s->cluster_sectors = 1 << (s->cluster_bits - 9); +@@ -172,6 +176,8 @@ + return -1; + } + ++#ifndef X49GP ++ + static int qcow_set_key(BlockDriverState *bs, const char *key) + { + BDRVQcowState *s = bs->opaque; +@@ -239,6 +245,8 @@ + } + } + ++#endif /* !(X49GP) */ ++ + /* 'allocate' is: + * + * 0 to not allocate. +@@ -344,6 +352,7 @@ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + bdrv_truncate(s->hd, cluster_offset + s->cluster_size); ++#ifndef X49GP + /* if encrypted, we must initialize the cluster + content which won't be written */ + if (s->crypt_method && +@@ -363,6 +372,7 @@ + } + } + } ++#endif /* !(X49GP) */ + } else { + cluster_offset |= QCOW_OFLAG_COMPRESSED | + (uint64_t)compressed_size << (63 - s->cluster_bits); +@@ -442,7 +452,7 @@ + return 0; + } + +-#if 0 ++#ifdef X49GP + + static int qcow_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +@@ -474,10 +484,12 @@ + ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + if (ret != n * 512) + return -1; ++#ifndef X49GP + if (s->crypt_method) { + encrypt_sectors(s, sector_num, buf, buf, n, 0, + &s->aes_decrypt_key); + } ++#endif /* !(X49GP) */ + } + nb_sectors -= n; + sector_num += n; +@@ -485,7 +497,8 @@ + } + return 0; + } +-#endif ++ ++#endif /* X49GP */ + + static int qcow_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +@@ -504,12 +517,15 @@ + index_in_cluster + n); + if (!cluster_offset) + return -1; ++#ifndef X49GP + if (s->crypt_method) { + encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, + &s->aes_encrypt_key); + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, + s->cluster_data, n * 512); +- } else { ++ } else ++#endif /* !(X49GP) */ ++ { + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + } + if (ret != n * 512) +@@ -522,6 +538,8 @@ + return 0; + } + ++#ifndef X49GP ++ + typedef struct QCowAIOCB { + BlockDriverAIOCB common; + int64_t sector_num; +@@ -554,12 +572,14 @@ + /* nothing to do */ + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* nothing to do */ ++#ifndef X49GP + } else { + if (s->crypt_method) { + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, + &s->aes_decrypt_key); + } ++#endif + } + + acb->nb_sectors -= acb->n; +@@ -673,6 +693,7 @@ + ret = -EIO; + goto fail; + } ++#ifndef X49GP + if (s->crypt_method) { + if (!acb->cluster_data) { + acb->cluster_data = qemu_mallocz(s->cluster_size); +@@ -684,7 +705,9 @@ + encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, + acb->n, 1, &s->aes_encrypt_key); + src_buf = acb->cluster_data; +- } else { ++ } else ++#endif /* !(X49GP) */ ++ { + src_buf = acb->buf; + } + acb->hd_aiocb = bdrv_aio_write(s->hd, +@@ -725,6 +748,8 @@ + qemu_aio_release(acb); + } + ++#endif /* !(X49GP) */ ++ + static void qcow_close(BlockDriverState *bs) + { + BDRVQcowState *s = bs->opaque; +@@ -887,19 +912,30 @@ + sizeof(BDRVQcowState), + qcow_probe, + qcow_open, ++#ifdef X49GP ++ qcow_read, ++ qcow_write, ++#else + NULL, + NULL, ++#endif + qcow_close, + qcow_create, + qcow_flush, + qcow_is_allocated, ++#ifndef X49GP + qcow_set_key, ++#else ++ NULL, ++#endif + qcow_make_empty, + ++#ifndef X49GP + .bdrv_aio_read = qcow_aio_read, + .bdrv_aio_write = qcow_aio_write, + .bdrv_aio_cancel = qcow_aio_cancel, + .aiocb_size = sizeof(QCowAIOCB), ++#endif + .bdrv_write_compressed = qcow_write_compressed, + .bdrv_get_info = qcow_get_info, + }; +diff -ur qemu-0.9.0/block-raw.c qemu/block-raw.c +--- qemu-0.9.0/block-raw.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-raw.c 2007-07-30 14:30:18.000000000 +0200 +@@ -27,6 +27,10 @@ + #ifndef _WIN32 + #include + ++#ifdef X49GP ++#define QEMU_TOOL ++#endif ++ + #ifndef QEMU_TOOL + #include "exec-all.h" + #endif +@@ -157,6 +161,7 @@ + return ret; + } + ++#ifndef X49GP + /***********************************************************/ + /* Unix AIO using POSIX AIO */ + +@@ -379,6 +384,7 @@ + pacb = &acb->next; + } + } ++#endif /* !(X49GP) */ + + static void raw_close(BlockDriverState *bs) + { +@@ -479,11 +485,12 @@ + raw_close, + raw_create, + raw_flush, +- ++#ifndef X49GP + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), ++#endif + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, +@@ -815,11 +822,12 @@ + raw_close, + NULL, + raw_flush, +- ++#ifndef X49GP + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), ++#endif + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_getlength = raw_getlength, +diff -ur qemu-0.9.0/block-vvfat.c qemu/block-vvfat.c +--- qemu-0.9.0/block-vvfat.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu/block-vvfat.c 2007-07-30 16:04:03.000000000 +0200 +@@ -41,9 +41,9 @@ + Note that DOS assumes the system files to be the first files in the + file system (test if the boot sector still relies on that fact)! */ + /* MAYBE TODO: write block-visofs.c */ +-/* TODO: call try_commit() only after a timeout */ + +-/* #define DEBUG */ ++#define DEBUG ++#undef DEBUG_SECTORS + + #ifdef DEBUG + +@@ -53,7 +53,7 @@ + #define stderr STDERR + FILE* stderr = NULL; + +-static void checkpoint(); ++static void checkpoint(const char *where); + + #ifdef __MINGW32__ + void nonono(const char* file, int line, const char* msg) { +@@ -70,9 +70,15 @@ + + #endif + ++#ifdef X49GP ++#define VOLUME_LABEL "X49GP-VVFAT" ++#else ++#define VOLUME_LABEL "QEMU-VVFAT" ++#endif ++ + /* dynamic array functions */ + typedef struct array_t { +- char* pointer; ++ unsigned char* pointer; + unsigned int size,next,item_size; + } array_t; + +@@ -144,9 +150,9 @@ + * index_to, but the order of all other elements is preserved. */ + static inline int array_roll(array_t* array,int index_to,int index_from,int count) + { +- char* buf; +- char* from; +- char* to; ++ unsigned char* buf; ++ unsigned char* from; ++ unsigned char* to; + int is; + + if(!array || +@@ -194,7 +200,7 @@ + /* return the index for a given member */ + int array_index(array_t* array, void* pointer) + { +- size_t offset = (char*)pointer - array->pointer; ++ size_t offset = (unsigned char*)pointer - array->pointer; + assert(offset >= 0); + assert((offset % array->item_size) == 0); + assert(offset/array->item_size < array->next); +@@ -204,6 +210,18 @@ + /* These structures are used to fake a disk and the VFAT filesystem. + * For this reason we need to use __attribute__((packed)). */ + ++#define BOOTCODE_SIZE 448 ++#define BOOTCODE_FAT32_SIZE 420 ++ ++typedef struct msdos_volume_info { ++ uint8_t drive_number; ++ uint8_t ignored; ++ uint8_t signature; ++ uint32_t id; ++ uint8_t volume_label[11]; ++ uint8_t fs_type[8]; ++} __attribute__((packed)) msdos_volume_info_t; ++ + typedef struct bootsector_t { + uint8_t jump[3]; + uint8_t name[8]; +@@ -221,11 +239,8 @@ + uint32_t total_sectors; + union { + struct { +- uint8_t drive_number; +- uint8_t current_head; +- uint8_t signature; +- uint32_t id; +- uint8_t volume_label[11]; ++ msdos_volume_info_t vi; ++ uint8_t boot_code[BOOTCODE_SIZE]; + } __attribute__((packed)) fat16; + struct { + uint32_t sectors_per_fat; +@@ -234,14 +249,43 @@ + uint32_t first_cluster_of_root_directory; + uint16_t info_sector; + uint16_t backup_boot_sector; +- uint16_t ignored; ++ uint16_t ignored[6]; ++ msdos_volume_info_t vi; ++ uint8_t boot_code[BOOTCODE_FAT32_SIZE]; + } __attribute__((packed)) fat32; + } u; +- uint8_t fat_type[8]; +- uint8_t ignored[0x1c0]; + uint8_t magic[2]; + } __attribute__((packed)) bootsector_t; + ++uint8_t dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 }; ++ ++uint8_t dummy_boot_code[BOOTCODE_SIZE] = ++ "\x0e" /* push cs */ ++ "\x1f" /* pop ds */ ++ "\xbe\x5b\x7c" /* mov si, */ ++/* write_msg: */ ++ "\xac" /* lodsb */ ++ "\x22\xc0" /* and al, al */ ++ "\x74\x0b" /* jz key_press */ ++ "\x56" /* push si */ ++ "\xb4\x0e" /* mov ah, 0eh */ ++ "\xbb\x07\x00" /* mov bx, 0007h */ ++ "\xcd\x10" /* int 10h */ ++ "\x5e" /* pop si */ ++ "\xeb\xf0" /* jmp write_msg */ ++/* key_press: */ ++ "\x32\xe4" /* xor ah, ah */ ++ "\xcd\x16" /* int 16h */ ++ "\xcd\x19" /* int 19h */ ++/* foo: */ ++ "\xeb\xfe" /* jmp foo */ ++/* message_text: */ ++ "This is not a bootable disk. Please insert a bootable floppy and\r\n" ++ "press any key to try again...\r\n"; ++ ++#define MSG_OFFSET_OFFSET 3 ++#define MESSAGE_OFFSET 29 /* Offset of message in above code */ ++ + typedef struct partition_t { + uint8_t attributes; /* 0x80 = bootable */ + uint8_t start_head; +@@ -340,7 +384,6 @@ + unsigned int current_cluster; + + /* write support */ +- BlockDriverState* write_target; + char* qcow_filename; + BlockDriverState* qcow; + void* fat2; +@@ -348,6 +391,7 @@ + array_t commits; + const char* path; + int downcase_short_names; ++ QEMUTimer *write_timer; + } BDRVVVFATState; + + +@@ -377,7 +421,7 @@ + /* direntry functions */ + + /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */ +-static inline int short2long_name(unsigned char* dest,const char* src) ++static inline int short2long_name(char* dest,const char* src) + { + int i; + for(i=0;i<129 && src[i];i++) { +@@ -423,7 +467,7 @@ + + static char is_volume_label(const direntry_t* direntry) + { +- return direntry->attributes == 0x28; ++ return (direntry->attributes & 0x1f) == 0x08; + } + + static char is_long_name(const direntry_t* direntry) +@@ -501,13 +545,16 @@ + { + if(s->fat_type==32) { + uint32_t* entry=array_get(&(s->fat),cluster); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %08x\n", __FUNCTION__, __LINE__, cluster, value)); + *entry=cpu_to_le32(value); + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %04x\n", __FUNCTION__, __LINE__, cluster, value & 0xffff)); + *entry=cpu_to_le16(value&0xffff); + } else { + int offset = (cluster*3/2); + unsigned char* p = array_get(&(s->fat), offset); ++ DLOG(fprintf(stderr, "%s:%u: cluster %u: %03x\n", __FUNCTION__, __LINE__, cluster, value & 0xfff)); + switch (cluster&1) { + case 0: + p[0] = value&0xff; +@@ -561,7 +608,6 @@ + case 32: s->max_fat_value=0x0fffffff; break; + default: s->max_fat_value=0; /* error... */ + } +- + } + + /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ +@@ -575,7 +621,7 @@ + + if(is_dot) { + entry=array_get_next(&(s->directory)); +- memset(entry->name,0x20,11); ++ memset(entry->name,' ',11); + memcpy(entry->name,filename,strlen(filename)); + return entry; + } +@@ -590,8 +636,8 @@ + i = 8; + + entry=array_get_next(&(s->directory)); +- memset(entry->name,0x20,11); +- strncpy(entry->name,filename,i); ++ memset(entry->name,' ',11); ++ strncpy((char *) entry->name,filename,i); + + if(j > 0) + for (i = 0; i < 3 && filename[j+1+i]; i++) +@@ -700,6 +746,8 @@ + continue; + } + ++ DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); ++ + /* create directory entry for this file */ + direntry=create_short_and_long_name(s, i, entry->d_name, + is_dot || is_dotdot); +@@ -726,6 +774,8 @@ + + /* create mapping for this file */ + if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { ++ DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, entry->d_name)); ++ + s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); + s->current_mapping->begin=0; + s->current_mapping->end=st.st_size; +@@ -778,9 +828,9 @@ + return 0; + } + +-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) ++static inline int32_t sector2cluster(BDRVVVFATState* s, off_t sector_num) + { +- return (sector_num-s->faked_sectors)/s->sectors_per_cluster; ++ return (sector_num - s->faked_sectors) / s->sectors_per_cluster; + } + + static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) +@@ -805,15 +855,19 @@ + static int init_directories(BDRVVVFATState* s, + const char* dirname) + { ++ msdos_volume_info_t *vi; + bootsector_t* bootsector; + mapping_t* mapping; + unsigned int i; + unsigned int cluster; ++ direntry_t *entry; ++ struct stat st; ++ size_t namelen; + + memset(&(s->first_sectors[0]),0,0x40*0x200); + +- s->cluster_size=s->sectors_per_cluster*0x200; +- s->cluster_buffer=malloc(s->cluster_size); ++ s->cluster_size = s->sectors_per_cluster * 0x200; ++ s->cluster_buffer = malloc(s->cluster_size); + assert(s->cluster_buffer); + + /* +@@ -823,18 +877,32 @@ + * spc is sectors_per_clusters, and + * fat_type = 12, 16 or 32. + */ +- i = 1+s->sectors_per_cluster*0x200*8/s->fat_type; +- s->sectors_per_fat=(s->sector_count+i)/i; /* round up */ ++ i = 1 + s->sectors_per_cluster * 0x200 * 8 / s->fat_type; ++ s->sectors_per_fat = (s->sector_count + i) / i; /* round up */ + + array_init(&(s->mapping),sizeof(mapping_t)); + array_init(&(s->directory),sizeof(direntry_t)); + ++ DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, dirname)); ++ + /* add volume label */ +- { +- direntry_t* entry=array_get_next(&(s->directory)); +- entry->attributes=0x28; /* archive | volume label */ +- snprintf(entry->name,11,"QEMU VVFAT"); +- } ++ stat(dirname, &st); ++ entry = array_get_next(&(s->directory)); ++ entry->attributes = 0x08; /* archive | volume label */ ++ memset(entry->name, ' ', 11); ++ namelen = strlen(VOLUME_LABEL); ++ if (namelen > 11) ++ namelen = 11; ++ memcpy(entry->name, VOLUME_LABEL, namelen); ++ entry->reserved[0] = entry->reserved[1] = 0; ++ entry->ctime = fat_datetime(st.st_ctime, 1); ++ entry->cdate = fat_datetime(st.st_ctime, 0); ++ entry->adate = fat_datetime(st.st_atime, 0); ++ entry->begin_hi = 0; ++ entry->mtime = fat_datetime(st.st_ctime, 1); ++ entry->mdate = fat_datetime(st.st_ctime, 0); ++ entry->begin = 0; ++ entry->size = 0; + + /* Now build FAT, and write back information into directory */ + init_fat(s); +@@ -842,6 +910,8 @@ + s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2; + s->cluster_count=sector2cluster(s, s->sector_count); + ++ DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, dirname)); ++ + mapping = array_get_next(&(s->mapping)); + mapping->begin = 0; + mapping->dir_index = 0; +@@ -910,16 +980,39 @@ + s->last_cluster_of_root_directory = mapping->end; + + /* the FAT signature */ +- fat_set(s,0,s->max_fat_value); ++ switch (s->fat_type) { ++ case 12: fat_set(s, 0, s->sector_count == 5760 ? 0xff9 : 0xff8); break; ++ case 16: fat_set(s, 0, 0xfff8); break; ++ case 32: fat_set(s, 0, 0x0ffffff0); break; ++ default: fat_set(s,0,s->max_fat_value); break; ++ } + fat_set(s,1,s->max_fat_value); + + s->current_mapping = NULL; + + bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200); +- bootsector->jump[0]=0xeb; +- bootsector->jump[1]=0x3e; +- bootsector->jump[2]=0x90; ++ ++ memcpy(bootsector->jump, dummy_boot_jump, 3); ++ bootsector->jump[1] = ((s->fat_type == 32 ? ++ (char *) &bootsector->u.fat32.boot_code : ++ (char *) &bootsector->u.fat16.boot_code) - ++ (char *) &bootsector) - 2; ++ if (s->fat_type == 32) { ++ int offset = (char *) &bootsector->u.fat32.boot_code - ++ (char *) &bootsector + MESSAGE_OFFSET + 0x7c00; ++ memcpy(bootsector->u.fat32.boot_code, dummy_boot_code, ++ BOOTCODE_FAT32_SIZE); ++ bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 0] = offset & 0xff; ++ bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 1] = offset >> 8; ++ } else { ++ memcpy(bootsector->u.fat16.boot_code, dummy_boot_code, BOOTCODE_SIZE); ++ } ++ ++#ifdef X49GP ++ memcpy(bootsector->name,"X49GP ",8); ++#else + memcpy(bootsector->name,"QEMU ",8); ++#endif + bootsector->sector_size=cpu_to_le16(0x200); + bootsector->sectors_per_cluster=s->sectors_per_cluster; + bootsector->reserved_sectors=cpu_to_le16(1); +@@ -927,7 +1020,6 @@ + bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); + bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); + bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */ +- s->fat.pointer[0] = bootsector->media_type; + bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); + bootsector->sectors_per_track=cpu_to_le16(s->bs->secs); + bootsector->number_of_heads=cpu_to_le16(s->bs->heads); +@@ -935,15 +1027,25 @@ + bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); + + /* LATER TODO: if FAT32, this is wrong */ +- bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */ +- bootsector->u.fat16.current_head=0; +- bootsector->u.fat16.signature=0x29; +- bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); ++ if (s->fat_type == 32) { ++ vi = &bootsector->u.fat32.vi; ++ memcpy(vi->fs_type, "FAT32 ", 8); ++ } else { ++ vi = &bootsector->u.fat16.vi; ++ memcpy(vi->fs_type, (s->fat_type == 12 ? "FAT12 " : "FAT16 "), 8); ++ } + +- memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11); +- memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8); +- bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; ++ /* assume this is hda (TODO) */ ++ vi->drive_number = s->fat_type == 12 ? 0 : 0x80; ++ vi->signature = 0x29; ++ vi->id = cpu_to_le32(0xfabe1afd); ++ memset(vi->volume_label, ' ', 11); ++ namelen = strlen(VOLUME_LABEL); ++ if (namelen > 11) ++ namelen = 11; ++ memcpy(vi->volume_label, VOLUME_LABEL, namelen); + ++ bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; + return 0; + } + +@@ -951,7 +1053,7 @@ + static BDRVVVFATState *vvv = NULL; + #endif + +-static int enable_write_target(BDRVVVFATState *s); ++static int enable_write(BDRVVVFATState *s); + static int is_consistent(BDRVVVFATState *s); + + static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags) +@@ -964,10 +1066,10 @@ + vvv = s; + #endif + +-DLOG(if (stderr == NULL) { +- stderr = fopen("vvfat.log", "a"); +- setbuf(stderr, NULL); +-}) ++ DLOG(if (stderr == NULL) { ++ stderr = fopen("vvfat.log", "a"); ++ setbuf(stderr, NULL); ++ }) + + s->bs = bs; + +@@ -983,17 +1085,20 @@ + s->first_sectors_number=0x40; + /* read only is the default for safety */ + bs->read_only = 1; +- s->qcow = s->write_target = NULL; ++ s->qcow = NULL; + s->qcow_filename = NULL; + s->fat2 = NULL; + s->downcase_short_names = 1; + +- if (!strstart(dirname, "fat:", NULL)) ++ if (!strstart(dirname, "fat:", NULL)) { ++ DLOG(fprintf(stderr, "%s:%u: dirname '%s' not \"fat:\"\n", __FUNCTION__, __LINE__, dirname)); + return -1; ++ } + + if (strstr(dirname, ":rw:")) { +- if (enable_write_target(s)) ++ if (enable_write(s)) { + return -1; ++ } + bs->read_only = 0; + } + +@@ -1026,8 +1131,11 @@ + bs->total_sectors=bs->cyls*bs->heads*bs->secs; + if (s->sector_count > bs->total_sectors) + s->sector_count = bs->total_sectors; +- if(init_directories(s, dirname)) ++ ++ if (init_directories(s, dirname)) { ++ DLOG(fprintf(stderr, "%s:%u: init_directories failed\n", __FUNCTION__, __LINE__)); + return -1; ++ } + + if(s->first_sectors_number==0x40) + init_mbr(s); +@@ -1037,6 +1145,8 @@ + bs->heads = bs->cyls = bs->secs = 0; + + // assert(is_consistent(s)); ++ ++ DLOG(fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__)); + return 0; + } + +@@ -1153,7 +1263,7 @@ + s->cluster = s->directory.pointer+offset + + 0x20*s->current_mapping->info.dir.first_dir_index; + assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); +- assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); ++ assert(s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size); + s->current_cluster = cluster_num; + return 0; + } +@@ -1227,6 +1337,18 @@ + direntry->attributes, + begin_of_direntry(direntry),le32_to_cpu(direntry->size)); + } ++ { ++ unsigned char *p = (void *) direntry; ++ int i; ++ ++ fprintf(stderr, "%p:\t", p); ++ for (i = 0; i < 16; i++) ++ fprintf(stderr, " %02x", *p++); ++ fprintf(stderr, "\n%p:\t", p); ++ for ( ; i < 32; i++) ++ fprintf(stderr, " %02x", *p++); ++ fprintf(stderr, "\n"); ++ } + } + + static void print_mapping(const mapping_t* mapping) +@@ -1243,6 +1365,9 @@ + uint8_t *buf, int nb_sectors) + { + BDRVVVFATState *s = bs->opaque; ++#ifdef DEBUG_SECTORS ++ int32_t orig_sector = sector_num; ++#endif + int i; + + for(i=0;ifaked_sectors) { + if(sector_numfirst_sectors_number) +@@ -1280,6 +1405,14 @@ + memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); + } + } ++ ++#ifdef DEBUG_SECTORS ++ for (i = 0; i < nb_sectors; i++) { ++ fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); ++ hexdump(buf + i * 0x200, 0x200); ++ } ++#endif ++ + return 0; + } + +@@ -1372,7 +1505,7 @@ + } + + typedef struct { +- unsigned char name[1024]; ++ char name[1024]; + int checksum, len; + int sequence_number; + } long_file_name; +@@ -1577,6 +1710,7 @@ + const char* basename; + + assert(mapping->mode & MODE_DELETED); ++ DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + basename = get_basename(mapping->path); +@@ -1702,6 +1836,7 @@ + assert(mapping->mode & MODE_DIRECTORY); + + assert(mapping->mode & MODE_DELETED); ++ DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode &= ~MODE_DELETED; + + if (strcmp(basename, basename2)) +@@ -1736,9 +1871,9 @@ + for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { + int cluster_count; + +-DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)); +- if (is_volume_label(direntries + i) || is_dot(direntries + i) || +- is_free(direntries + i)) ++DLOG(if (!is_free(direntries + i)) { fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i); }) ++ ++ if (is_volume_label(direntries + i) || is_dot(direntries + i) || is_free(direntries + i)) + continue; + + subret = parse_long_name(&lfn, direntries + i); +@@ -1806,7 +1941,10 @@ + int i, check; + int used_clusters_count = 0; + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ + /* + * - get modified FAT + * - compare the two FATs (TODO) +@@ -1825,10 +1963,11 @@ + s->fat2 = malloc(size); + memcpy(s->fat2, s->fat.pointer, size); + } +- check = vvfat_read(s->bs, +- s->first_sectors_number, s->fat2, s->sectors_per_fat); ++ check = vvfat_read(s->bs, s->first_sectors_number, ++ s->fat2, s->sectors_per_fat); + if (check) { + fprintf(stderr, "Could not copy fat\n"); ++ DLOG(fprintf(stderr, "%s:%u: copy fat failed\n", __FUNCTION__, __LINE__)); + return 0; + } + assert (s->used_clusters); +@@ -1839,12 +1978,15 @@ + + /* mark every mapped file/directory as deleted. + * (check_directory_consistency() will unmark those still present). */ +- if (s->qcow) ++ if (s->qcow) { + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); +- if (mapping->first_mapping_index < 0) ++ if (mapping->first_mapping_index < 0) { ++ DLOG(fprintf(stderr, "%s:%u: mark delete: ", __FUNCTION__, __LINE__); print_mapping(mapping)); + mapping->mode |= MODE_DELETED; ++ } + } ++ } + + used_clusters_count = check_directory_consistency(s, 0, s->path); + if (used_clusters_count <= 0) { +@@ -1869,9 +2011,12 @@ + } + } + +- if (check != used_clusters_count) ++ if (check != used_clusters_count) { ++ DLOG(fprintf(stderr, "%s:%u: check: %u, used %u\n", __FUNCTION__, __LINE__, check, used_clusters_count)); + return 0; ++ } + ++ DLOG(fprintf(stderr, "%s:%u: return used %u\n", __FUNCTION__, __LINE__, used_clusters_count)); + return used_clusters_count; + } + +@@ -1928,6 +2073,8 @@ + ((next_mapping = array_get(&(s->mapping), index + 1)) && + next_mapping->begin >= end))); + ++ DLOG(fprintf(stderr, "insert mapping %u:\n", index); print_mapping(mapping)); ++ + if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) + s->current_mapping = array_get(&(s->mapping), + s->current_mapping - first_mapping); +@@ -1940,6 +2087,8 @@ + mapping_t* mapping = array_get(&(s->mapping), mapping_index); + mapping_t* first_mapping = array_get(&(s->mapping), 0); + ++ DLOG(fprintf(stderr, "remove mapping %u:\n", mapping_index); print_mapping(mapping)); ++ + /* free mapping */ + if (mapping->first_mapping_index < 0) + free(mapping->path); +@@ -2090,7 +2239,7 @@ + int ret, i; + uint32_t c; + +-DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index)); ++ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index)); + + assert(direntry); + assert(mapping); +@@ -2130,7 +2279,7 @@ + s->sectors_per_cluster); + if (ret) + return ret; +- assert(!strncmp(s->directory.pointer, "QEMU", 4)); ++ assert(!strncmp((char *) s->directory.pointer, VOLUME_LABEL, strlen(VOLUME_LABEL))); + current_dir_index += factor; + } + +@@ -2164,7 +2313,7 @@ + uint32_t first_cluster = c; + mapping_t* mapping = find_mapping_for_cluster(s, c); + uint32_t size = filesize_of_direntry(direntry); +- char* cluster = malloc(s->cluster_size); ++ unsigned char* cluster = malloc(s->cluster_size); + uint32_t i; + int fd = 0; + +@@ -2217,13 +2366,13 @@ + + #ifdef DEBUG + /* test, if all mappings point to valid direntries */ +-static void check1(BDRVVVFATState* s) ++static void check1(BDRVVVFATState* s, const char *where) + { + int i; + for (i = 0; i < s->mapping.next; i++) { + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { +- fprintf(stderr, "deleted\n"); ++ DLOG(fprintf(stderr, "%s: deleted\n", where); print_mapping(mapping)); + continue; + } + assert(mapping->dir_index >= 0); +@@ -2238,7 +2387,7 @@ + } + + /* test, if all direntries have mappings */ +-static void check2(BDRVVVFATState* s) ++static void check2(BDRVVVFATState* s, const char *where) + { + int i; + int first_mapping = -1; +@@ -2485,7 +2634,9 @@ + mapping_t* mapping = array_get(&(s->mapping), i); + if (mapping->mode & MODE_DELETED) { + direntry_t* entry = array_get(&(s->directory), +- mapping->dir_index); ++ mapping->dir_index); ++ ++ DLOG(fprintf(stderr, "%s:%u: ", __FUNCTION__, __LINE__); print_mapping(mapping); print_direntry(entry)); + + if (is_free(entry)) { + /* remove file/directory */ +@@ -2515,14 +2666,15 @@ + next_dir_index - first_dir_index); + + deleted++; ++ } else { ++ if (unlink(mapping->path)) ++ return -4; ++ deleted++; + } +- } else { +- if (unlink(mapping->path)) +- return -4; +- deleted++; ++ ++ DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); ++ remove_mapping(s, i); + } +- DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry)); +- remove_mapping(s, i); + } + } + } +@@ -2530,6 +2682,20 @@ + return 0; + } + ++static int have_deletes(BDRVVVFATState* s) ++{ ++ int i; ++ ++ for (i = 0; i < s->mapping.next; i++) { ++ mapping_t* mapping = array_get(&(s->mapping), i); ++ if (mapping->mode & MODE_DELETED) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ + /* + * synchronize mapping with new state: + * +@@ -2543,8 +2709,10 @@ + int ret = 0; + + /* the real meat are the commits. Nothing to do? Move along! */ +- if (s->commits.next == 0) ++ if ((0 == s->commits.next) && (0 == have_deletes(s))) { ++ DLOG(fprintf(stderr, "%s:%u: nothing to do\n", __FUNCTION__, __LINE__)); + return 0; ++ } + + vvfat_close_current_file(s); + +@@ -2584,26 +2752,48 @@ + + memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); + return 0; + } + + static int try_commit(BDRVVVFATState* s) + { + vvfat_close_current_file(s); +-DLOG(checkpoint()); ++ ++DLOG(checkpoint(__FUNCTION__)); ++ + if(!is_consistent(s)) + return -1; ++ + return do_commit(s); + } + ++static void ++vvfat_write_timer(void *opaque) ++{ ++ BDRVVVFATState *s = opaque; ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ ++DLOG(checkpoint("vvfat_write_timer: before try_commits")); ++ ++ try_commit(s); ++ ++DLOG(checkpoint("vvfat_write_timer: after try_commits")); ++} ++ + static int vvfat_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) + { + BDRVVVFATState *s = bs->opaque; ++ mapping_t* mapping; ++#ifdef DEBUG_SECTORS ++ int32_t orig_sector = sector_num; ++#endif ++ int64_t start_cluster, end_cluster; + int i, ret; + +-DLOG(checkpoint()); ++DLOG(checkpoint(__FUNCTION__)); + + vvfat_close_current_file(s); + +@@ -2613,12 +2803,35 @@ + * - do not allow to write non-ASCII filenames + */ + +- if (sector_num < s->first_sectors_number) ++ if (sector_num < s->first_sectors_number) { ++ DLOG(fprintf(stderr, "%s:%u: sector: %u nb %u (first: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->first_sectors_number)); + return -1; ++ } + +- for (i = sector2cluster(s, sector_num); +- i <= sector2cluster(s, sector_num + nb_sectors - 1);) { +- mapping_t* mapping = find_mapping_for_cluster(s, i); ++#ifdef DEBUG_SECTORS ++ for (i = 0; i < nb_sectors; i++) { ++ fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i); ++ hexdump(buf + i * 0x200, 0x200); ++ } ++#endif ++ ++ DLOG(fprintf(stderr, "%s:%u: check mappings, sector: %u nb %u (faked: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->faked_sectors)); ++ ++ if (sector_num >= s->faked_sectors) { ++ start_cluster = sector2cluster(s, sector_num); ++ } else { ++ start_cluster = 0; ++ } ++ if (sector_num + nb_sectors - 1 >= s->faked_sectors) { ++ end_cluster = sector2cluster(s, sector_num + nb_sectors - 1); ++ } else { ++ end_cluster = -1; ++ } ++ ++ for (i = start_cluster; i <= end_cluster; ) { ++ DLOG(fprintf(stderr, "%s:%u: cluster %u\n", __FUNCTION__, __LINE__, i)); ++ mapping = find_mapping_for_cluster(s, i); ++ DLOG(fprintf(stderr, "%s:%u: mapping %p\n", __FUNCTION__, __LINE__, mapping)); + if (mapping) { + if (mapping->read_only) { + fprintf(stderr, "Tried to write to write-protected file %s\n", +@@ -2662,30 +2875,25 @@ + } + } + i = mapping->end; +- } else ++ } else { + i++; ++ } + } + + /* + * Use qcow backend. Commit later. + */ +-DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); ++ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); + ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors); + if (ret < 0) { + fprintf(stderr, "Error writing to qcow backend\n"); + return ret; + } + +- for (i = sector2cluster(s, sector_num); +- i <= sector2cluster(s, sector_num + nb_sectors - 1); i++) +- if (i >= 0) +- s->used_clusters[i] |= USED_ALLOCATED; +- +-DLOG(checkpoint()); +- /* TODO: add timeout */ +- try_commit(s); ++ for (i = start_cluster; i <= end_cluster; i++) ++ s->used_clusters[i] |= USED_ALLOCATED; + +-DLOG(checkpoint()); ++ qemu_mod_timer(s->write_timer, qemu_get_clock(rt_clock) + ticks_per_sec); + return 0; + } + +@@ -2701,49 +2909,62 @@ + return 1; + } + +-static int write_target_commit(BlockDriverState *bs, int64_t sector_num, +- const uint8_t* buffer, int nb_sectors) { +- BDRVVVFATState* s = bs->opaque; +- return try_commit(s); +-} +- +-static void write_target_close(BlockDriverState *bs) { +- BDRVVVFATState* s = bs->opaque; +- bdrv_delete(s->qcow); +- free(s->qcow_filename); +-} +- +-static BlockDriver vvfat_write_target = { +- "vvfat_write_target", 0, NULL, NULL, NULL, +- write_target_commit, +- write_target_close, +- NULL, NULL, NULL +-}; +- +-static int enable_write_target(BDRVVVFATState *s) ++static int enable_write(BDRVVVFATState *s) + { +- int size = sector2cluster(s, s->sector_count); ++ int error; ++ int size; ++ ++ DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__)); ++ ++ size = sector2cluster(s, s->sector_count); + s->used_clusters = calloc(size, 1); + + array_init(&(s->commits), sizeof(commit_t)); + + s->qcow_filename = malloc(1024); + get_tmp_filename(s->qcow_filename, 1024); +- if (bdrv_create(&bdrv_qcow, +- s->qcow_filename, s->sector_count, "fat:", 0) < 0) ++ error = bdrv_create(&bdrv_qcow, s->qcow_filename, s->sector_count, "", 0); ++ if (error < 0) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_create '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); + return -1; ++ } ++ + s->qcow = bdrv_new(""); +- if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0) ++ if (s->qcow == NULL) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_new: Out of memory\n", __FUNCTION__, __LINE__)); ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif + return -1; ++ } + ++ error = bdrv_open(s->qcow, s->qcow_filename, 0); ++ if (error < 0) { ++ DLOG(fprintf(stderr, "%s:%u: bdrv_open '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error)); + #ifndef _WIN32 +- unlink(s->qcow_filename); ++ unlink(s->qcow_filename); + #endif ++ bdrv_delete(s->qcow); ++ return -1; ++ } + +- s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1); +- s->bs->backing_hd->drv = &vvfat_write_target; +- s->bs->backing_hd->opaque = s; ++ s->write_timer = qemu_new_timer(rt_clock, vvfat_write_timer, s); ++ if (NULL == s->write_timer) { ++ DLOG(fprintf(stderr, "%s:%u: write_timer: Out of memory\n", __FUNCTION__, __LINE__)); ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif ++ bdrv_delete(s->qcow); ++ return -1; ++ } ++ ++ s->qcow->is_temporary = 1; ++ ++#ifndef _WIN32 ++ unlink(s->qcow_filename); ++#endif + ++ DLOG(fprintf(stderr, "%s:%u: write enabled\n", __FUNCTION__, __LINE__)); + return 0; + } + +@@ -2751,10 +2972,24 @@ + { + BDRVVVFATState *s = bs->opaque; + ++ if (qemu_timer_pending(s->write_timer)) { ++ qemu_del_timer(s->write_timer); ++ vvfat_write_timer(s); ++ } ++ + vvfat_close_current_file(s); ++ ++ if (s->qcow) { ++ qemu_free(s->qcow_filename); ++ ++ bdrv_delete(s->qcow); ++ s->qcow = NULL; ++ } ++ + array_free(&(s->fat)); + array_free(&(s->directory)); + array_free(&(s->mapping)); ++ + if(s->cluster_buffer) + free(s->cluster_buffer); + } +@@ -2774,10 +3009,16 @@ + }; + + #ifdef DEBUG +-static void checkpoint() { ++static void ++checkpoint(const char *where) ++{ ++ DLOG(fprintf(stderr, "%s:%u: checkpoint(%s)\n", __FUNCTION__, __LINE__, where)); ++ + assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); +- check1(vvv); +- check2(vvv); ++ DLOG(fprintf(stderr, "checkpoint(%s): call check1()\n", where)); ++ check1(vvv, where); ++ DLOG(fprintf(stderr, "checkpoint(%s): call check2()\n", where)); ++ check2(vvv, where); + assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); + #if 0 + if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf) +@@ -2793,10 +3034,11 @@ + direntry = array_get(&(vvv->directory), mapping->dir_index); + assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0); + #endif ++ DLOG(fprintf(stderr, "checkpoint(%s): done\n", where)); + return; + /* avoid compiler warnings: */ + hexdump(NULL, 100); +- remove_mapping(vvv, NULL); ++ remove_mapping(vvv, 0); + print_mapping(NULL); + print_direntry(NULL); + } diff --git a/qemu/patches/qemu-0.9.0-x49gp-build-libqemu.patch b/qemu/patches/qemu-0.9.0-x49gp-build-libqemu.patch new file mode 100644 index 0000000..06f72ba --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-build-libqemu.patch @@ -0,0 +1,15 @@ +--- qemu-0.9.0/Makefile 2007-07-26 11:10:25.000000000 +0200 ++++ qemu/Makefile 2007-07-26 11:10:38.000000000 +0200 +@@ -32,10 +32,10 @@ + endif + endif + +-all: $(TOOLS) $(DOCS) recurse-all ++all: recurse-all + + subdir-%: dyngen$(EXESUF) +- $(MAKE) -C $(subst subdir-,,$@) all ++ $(MAKE) -C $(subst subdir-,,$@) libqemu.a + + recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) + diff --git a/qemu/patches/qemu-0.9.0-x49gp-debug-unassigned.patch b/qemu/patches/qemu-0.9.0-x49gp-debug-unassigned.patch new file mode 100644 index 0000000..9fca6a1 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-debug-unassigned.patch @@ -0,0 +1,36 @@ +diff -ur qemu/exec.c qemu-0.9.0/exec.c +--- qemu/exec.c 2007-02-06 00:01:54.000000000 +0100 ++++ qemu-0.9.0/exec.c 2007-07-10 09:14:31.000000000 +0200 +@@ -41,7 +41,7 @@ + //#define DEBUG_TB_INVALIDATE + //#define DEBUG_FLUSH + //#define DEBUG_TLB +-//#define DEBUG_UNASSIGNED ++#define DEBUG_UNASSIGNED + + /* make various TB consistency checks */ + //#define DEBUG_TB_CHECK +@@ -1812,10 +1812,14 @@ + return p->phys_offset; + } + ++CPUState *__GLOBAL_env; ++ + static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) + { + #ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read 0x%08x\n", (int)addr); ++ cpu_dump_state(__GLOBAL_env, stdout, fprintf, 0); ++ abort(); + #endif + return 0; + } +@@ -1824,6 +1828,8 @@ + { + #ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); ++ cpu_dump_state(__GLOBAL_env, stdout, fprintf, 0); ++ abort(); + #endif + } + diff --git a/qemu/patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch b/qemu/patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch new file mode 100644 index 0000000..cdb7db6 --- /dev/null +++ b/qemu/patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch @@ -0,0 +1,17 @@ +--- qemu-0.9.0/exec.c 2007-07-23 13:57:29.000000000 +0200 ++++ qemu/exec.c 2007-07-23 13:53:06.000000000 +0200 +@@ -1942,9 +1942,11 @@ + cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); + io_mem_nb = 5; + +- /* alloc dirty bits array */ +- phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); +- memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); ++ if (phys_ram_size) { ++ /* alloc dirty bits array */ ++ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); ++ memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); ++ } + } + + /* mem_read and mem_write are arrays of functions containing the diff --git a/qemu/patches/qemu-2ndbootdevice_04.diff b/qemu/patches/qemu-2ndbootdevice_04.diff new file mode 100644 index 0000000..4220ec9 --- /dev/null +++ b/qemu/patches/qemu-2ndbootdevice_04.diff @@ -0,0 +1,165 @@ +--- vl.h 2007-02-05 21:20:30.000000000 +0100 ++++ vl.h_2 2007-03-14 16:22:14.000000000 +0100 +@@ -683,6 +683,9 @@ + + typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, + int boot_device, ++#ifdef TARGET_I386 ++ int boot_device_2, ++#endif + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +--- vl.c 2007-02-05 21:46:05.000000000 +0100 ++++ vl.c_2.c 2007-03-14 15:16:49.000000000 +0100 +@@ -131,6 +131,7 @@ + const char* keyboard_layout = NULL; + int64_t ticks_per_sec; + int boot_device = 'c'; ++int boot_device_2 = 'd'; + int ram_size; + int pit_min_timer_count = 0; + int nb_nics; +@@ -6021,7 +6022,11 @@ + "-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 image (cdrom is ide1 master)\n" ++#ifdef TARGET_I386 ++ "-boot d1(,d2) boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" ++#else + "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" ++#endif + "-snapshot write to temporary files instead of disk image files\n" + #ifdef CONFIG_SDL + "-no-quit disable SDL window close capability\n" +@@ -6721,6 +6734,15 @@ + break; + case QEMU_OPTION_boot: + boot_device = optarg[0]; ++#ifdef TARGET_I386 ++ if (strlen(optarg) == 3) { //we have a second bootdevice ++ boot_device_2 = optarg[2]; ++ if (boot_device_2 != 'a' && boot_device_2 != 'c' && boot_device_2 != 'd') { ++ fprintf(stderr, "qemu: invalid second boot device '%c'\n", boot_device_2); ++ exit(1); ++ } ++ } ++#endif + if (boot_device != 'a' && + #if defined(TARGET_SPARC) || defined(TARGET_I386) + // Network boot +@@ -7199,8 +7220,11 @@ + qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); + } + } +- ++#ifdef TARGET_I386 ++ machine->init(ram_size, vga_ram_size, boot_device, boot_device_2, ++#else + machine->init(ram_size, vga_ram_size, boot_device, ++#endif + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); + +--- hw/pc.c 2007-02-02 04:13:18.000000000 +0100 ++++ hw/pc.c_2 2007-03-14 15:58:38.000000000 +0100 +@@ -154,7 +154,7 @@ + } + + /* hd_table must contain 4 block drivers */ +-static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) ++static void cmos_init(int ram_size, int boot_device, int boot_device_2, BlockDriverState **hd_table) + { + RTCState *s = rtc_state; + int val; +@@ -185,19 +185,32 @@ + rtc_set_memory(s, 0x34, val); + rtc_set_memory(s, 0x35, val >> 8); + ++ int bd2_val; ++ switch(boot_device_2) { ++ case 'a': ++ bd2_val = 0x10; ++ break; ++ case 'c': ++ bd2_val = 0x20; ++ break; ++ case 'd': ++ bd2_val = 0x30; ++ break; ++ } ++ + switch(boot_device) { + case 'a': + case 'b': +- rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x01); /* floppy boot */ + if (!fd_bootchk) +- rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ ++ rtc_set_memory(s, 0x38, bd2_val | 0x01); /* disable signature check */ + break; + default: + case 'c': +- rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x02); /* hard drive boot */ + break; + case 'd': +- rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ ++ rtc_set_memory(s, 0x3d, bd2_val | 0x03); /* CD-ROM boot */ + break; + } + +@@ -443,7 +459,8 @@ + } + + /* PC hardware initialisation */ +-static void pc_init1(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init1(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, +@@ -692,7 +709,7 @@ + + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + +- cmos_init(ram_size, boot_device, bs_table); ++ cmos_init(ram_size, boot_device, boot_device_2, bs_table); + + if (pci_enabled && usb_enabled) { + usb_uhci_init(pci_bus, piix3_devfn + 2); +@@ -730,27 +747,29 @@ + #endif + } + +-static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init_pci(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) + { +- pc_init1(ram_size, vga_ram_size, boot_device, ++ pc_init1(ram_size, vga_ram_size, boot_device, boot_device_2, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 1); + } + +-static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, ++static void pc_init_isa(int ram_size, int vga_ram_size, ++ int boot_device, int boot_device_2, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) + { +- pc_init1(ram_size, vga_ram_size, boot_device, ++ pc_init1(ram_size, vga_ram_size, boot_device, boot_device_2, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0); diff --git a/qemu/prepare.sh b/qemu/prepare.sh new file mode 100755 index 0000000..c6f66cd --- /dev/null +++ b/qemu/prepare.sh @@ -0,0 +1,61 @@ +# get/update QEMU + +# export CVS_RSH="ssh" +# cvs -z3 -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/qemu co -r "release_0_9_0" qemu + +rm -rf qemu +tar xzvf qemu-0.9.0.tar.gz +mv qemu-0.9.0 qemu + +# patch qemu sources +cd qemu + +#qemu hotfix for qcow2 +patch -p0 -u < ../patches/qemu-0.9.0-qcow2.diff + +#qemu gcc4 patches +patch -p1 -u < ../patches/qemu-0.9.0-gcc4.patch +patch -p1 -u < ../patches/qemu-0.7.2-dyngen-check-stack-clobbers.patch +patch -p1 -u < ../patches/qemu-0.7.2-gcc4-opts.patch +patch -p1 -u < ../patches/qemu-0.8.0-gcc4-hacks.patch + +#qemu OS X86 patches +patch -p1 -u < ../patches/qemu-0.9.0-enforce-16byte-stack-boundary.patch +patch -p1 -u -f < ../patches/qemu-0.9.0-i386-FORCE_RET.patch +patch -p1 -u < ../patches/qemu-0.9.0-osx-intel-port.patch + +patch -p1 -u < ../patches/qemu-0.8.0-osx-bugfix.patch + +# arm patches +patch -p1 -u < ../patches/qemu-0.9.0-arm-shift.patch + +# x49gp patches +patch -p1 -u < ../patches/qemu-0.9.0-sparc-compile-flags.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-load-store-le.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-clobber.patch +patch -p1 -u < ../patches/qemu-0.9.0-sparc-register.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-dump-state.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-mmu.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-arm-semihosting.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-debug-unassigned.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-phys_ram_dirty.patch +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-block.patch + +# only build libqemu.a +patch -p1 -u < ../patches/qemu-0.9.0-x49gp-build-libqemu.patch + + +# configure +if [ "`uname -m`" = "sparc64" ]; then + STUB=sparc32 +fi + +if [ "`uname -s`" = "Darwin" ]; then + OPTIONS="--disable-gcc-check" +fi + +OPTIONS="${OPTIONS} --disable-gfx-check" + +${STUB} ./configure ${OPTIONS} --target-list=arm-softmmu + +cd .. diff --git a/qemu/qemu-0.9.0.tar.gz b/qemu/qemu-0.9.0.tar.gz new file mode 100644 index 0000000..07f9ce7 Binary files /dev/null and b/qemu/qemu-0.9.0.tar.gz differ diff --git a/qemu/qemu-git/.svn/all-wcprops b/qemu/qemu-git/.svn/all-wcprops new file mode 100644 index 0000000..e1d1e76 --- /dev/null +++ b/qemu/qemu-git/.svn/all-wcprops @@ -0,0 +1,431 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git +END +qemu-queue.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/qemu-queue.h +END +ppc-dis.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/ppc-dis.c +END +gdbstub.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdbstub.h +END +alpha-dis.c +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/alpha-dis.c +END +cutils.c +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cutils.c +END +softmmu_exec.h +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/softmmu_exec.h +END +VERSION +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/VERSION +END +hppa.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/hppa.ld +END +ppc64.ld +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/ppc64.ld +END +config.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/config.h +END +sh4-dis.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/sh4-dis.c +END +elf.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/elf.h +END +x86_64.ld +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/x86_64.ld +END +ia64.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/ia64.ld +END +mips-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/mips-dis.c +END +feature_to_c.sh +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/feature_to_c.sh +END +softmmu_template.h +K 25 +svn:wc:ra_dav:version-url +V 58 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/softmmu_template.h +END +sparc64.ld +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/sparc64.ld +END +qemu-common.h +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/qemu-common.h +END +m68k-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/m68k-dis.c +END +kvm.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/kvm.h +END +hostregs_helper.h +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/hostregs_helper.h +END +Makefile-small +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/Makefile-small +END +dis-asm.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/dis-asm.h +END +disas.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/disas.c +END +translate-all.c +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/translate-all.c +END +i386-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/i386-dis.c +END +cache-utils.h +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cache-utils.h +END +disas.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/disas.h +END +cpu-exec.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cpu-exec.c +END +dyngen-exec.h +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/dyngen-exec.h +END +s390.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/s390.ld +END +gen-icount.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gen-icount.h +END +cris-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cris-dis.c +END +Makefile-small.hw +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/Makefile-small.hw +END +rules.mak +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/rules.mak +END +bswap.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/bswap.h +END +cpu-common.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cpu-common.h +END +exec.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/exec.c +END +mips.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/mips.ld +END +module.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/module.h +END +qemu-log.h +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/qemu-log.h +END +arm.ld +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/arm.ld +END +arm-dis.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/arm-dis.c +END +tcg-runtime.c +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg-runtime.c +END +exec-all.h +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/exec-all.h +END +softmmu_defs.h +K 25 +svn:wc:ra_dav:version-url +V 54 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/softmmu_defs.h +END +qemu-lock.h +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/qemu-lock.h +END +alpha.ld +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/alpha.ld +END +microblaze-dis.c +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/microblaze-dis.c +END +configure-small +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/configure-small +END +create_config +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/create_config +END +softmmu_header.h +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/softmmu_header.h +END +s390-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/s390-dis.c +END +def-helper.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/def-helper.h +END +ioport.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/ioport.h +END +sparc-dis.c +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/sparc-dis.c +END +Makefile-small.objs +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/Makefile-small.objs +END +ppc.ld +K 25 +svn:wc:ra_dav:version-url +V 46 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/ppc.ld +END +m68k.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/m68k.ld +END +cpu-all.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cpu-all.h +END +hppa-dis.c +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/hppa-dis.c +END +targphys.h +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/targphys.h +END +i386.ld +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/i386.ld +END +host-utils.c +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/host-utils.c +END +cpu-defs.h +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/cpu-defs.h +END +qemu-malloc.c +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/qemu-malloc.c +END +osdep.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/osdep.h +END +host-utils.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/host-utils.h +END +sparc.ld +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/sparc.ld +END +Makefile-small.target +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/Makefile-small.target +END diff --git a/qemu/qemu-git/.svn/entries b/qemu/qemu-git/.svn/entries new file mode 100644 index 0000000..8eb1856 --- /dev/null +++ b/qemu/qemu-git/.svn/entries @@ -0,0 +1,2457 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +qemu-queue.h +file + + + + +2013-08-23T00:54:48.000000Z +0c132c8fa63263455927f5fcbd174686 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +22520 + +ppc-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +9145854436e1407fbdbc27f34c400567 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +242653 + +gdbstub.h +file + + + + +2013-08-23T00:54:48.000000Z +d68f7703929230ca98120fc27a60432a +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1150 + +alpha-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +8f661d4b95493866c85d523f31268fbb +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +81711 + +cutils.c +file + + + + +2013-08-23T00:54:48.000000Z +6055c6ea6ae999989af30ede0f1df31f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +5768 + +softmmu_exec.h +file + + + + +2013-08-23T00:54:48.000000Z +3da5cf17d38cb866b9dbf7218d7b1003 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2732 + +VERSION +file + + + + +2013-08-23T00:54:48.000000Z +4e289a05752b397d16fc9df5d253730e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8 + +hppa.ld +file + + + + +2013-08-23T00:54:48.000000Z +ec3aee04b6a1c9f2e8c8b65d131bf1bb +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8217 + +ppc64.ld +file + + + + +2013-08-23T00:54:48.000000Z +d9dc8787ce7347c27765c160dae8a262 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +7972 + +config.h +file + + + + +2013-08-23T00:54:48.000000Z +b494924ce54b1b87d12e1d6930cd69f2 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +52 + +x86_64.ld +file + + + + +2013-08-23T00:54:48.000000Z +1eb5eff47c629f872a50b2528a227d02 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +6530 + +elf.h +file + + + + +2013-08-23T00:54:48.000000Z +e6db36778f428581ce418e58a9ce79bf +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +43975 + +sh4-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +41ed2b20e9801ad5ea8c539184b53f4b +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +84880 + +ia64.ld +file + + + + +2013-08-23T00:54:48.000000Z +ffaeab9450f96b3256f5e81155a6d368 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8437 + +mips-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +289cec416842cfcfebcff17c9ee46cd2 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +209629 + +feature_to_c.sh +file + + + + +2013-08-23T00:54:48.000000Z +322f42519da96b887d2f5f79c7842a6f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2169 + +default-configs +dir + +softmmu_template.h +file + + + + +2013-08-23T00:54:48.000000Z +68075600378c1c712bfa465facc4be3d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +12154 + +tcg +dir + +sparc64.ld +file + + + + +2013-08-23T00:54:48.000000Z +34f0d9e6a049fc2fffa87b157b13849a +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4535 + +qemu-common.h +file + + + + +2013-08-23T00:54:48.000000Z +54d48d7cb99abcfc5ef1c7cc967c20a0 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +7800 + +m68k-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +4b923dd0894376c51c47415d4a8cb709 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +216646 + +kvm.h +file + + + + +2013-08-23T00:54:48.000000Z +c63b97d2c1eda57f05ec531aef0c08c5 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3915 + +hostregs_helper.h +file + + + + +2013-08-23T00:54:48.000000Z +35322c311d001f48f74b1c69548cd2d3 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1809 + +Makefile-small +file + + + + +2013-08-23T00:54:48.000000Z +7b44b7b9b539142d8d541c2883c2357e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3016 + +dis-asm.h +file + + + + +2013-08-23T00:54:48.000000Z +85ba49dd508b0b52b5dfd67ef572f332 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +18447 + +disas.c +file + + + + +2013-08-23T00:54:48.000000Z +9e9f009cd185a04aea1013a9ce64fa7c +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +11250 + +translate-all.c +file + + + + +2013-08-23T00:54:48.000000Z +6795fed5231bdeee54eb45fd208fbe3a +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +5158 + +cache-utils.h +file + + + + +2013-08-23T00:54:48.000000Z +faa35302b68deeb205232f1b4fee449c +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1173 + +i386-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +ca2316cce90f6d5fbb8b5f1d8132a7da +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +162885 + +disas.h +file + + + + +2013-08-23T00:54:48.000000Z +6868a9de9f59ba66f66312e0da67939f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1151 + +cpu-exec.c +file + + + + +2013-08-23T00:54:48.000000Z +59e77f1d8d9adeffde74e4a65f572da7 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +42486 + +s390.ld +file + + + + +2013-08-23T00:54:48.000000Z +77137d74a30442f6c4832d66f4e09453 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +7042 + +dyngen-exec.h +file + + + + +2013-08-23T00:54:48.000000Z +7a070ce4622fe25362fa388fe52e1061 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3592 + +gen-icount.h +file + + + + +2013-08-23T00:54:48.000000Z +1969909f8badaa1ce9bddb7b9dab6238 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1240 + +cris-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +d736bf46d21efe1bd5f3b750e4ed309b +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +82192 + +Makefile-small.hw +file + + + + +2013-08-23T00:54:48.000000Z +9c73afcd364803716d500eb23f929fed +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +518 + +rules.mak +file + + + + +2013-08-23T00:54:48.000000Z +a27b85e4993441049f821c6b6f66945d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1613 + +bswap.h +file + + + + +2013-08-23T00:54:48.000000Z +d42b019d2523a4afa27f3c599d3ca238 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4853 + +cpu-common.h +file + + + + +2013-08-23T00:54:48.000000Z +134c73d2fce6070383c7adf28ca097cb +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3658 + +exec.c +file + + + + +2013-08-23T00:54:48.000000Z +d97277018bf227d70cc04318babb8fbb +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +113101 + +mips.ld +file + + + + +2013-08-23T00:54:48.000000Z +e3a24e62417718f5495f40d749086e3f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8622 + +module.h +file + + + + +2013-08-23T00:54:48.000000Z +bf1a107116cc0b63db4e9444b899f5ff +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1077 + +qemu-log.h +file + + + + +2013-08-23T00:54:48.000000Z +c2f4d0ed055cd28a8d460e5d59cb543e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2146 + +arm.ld +file + + + + +2013-08-23T00:54:48.000000Z +56b2c5de693a7abcb69240e74106ea18 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4756 + +arm-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +3560b11f9ceb4f58155f1347411d7742 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +160380 + +tcg-runtime.c +file + + + + +2013-08-23T00:54:48.000000Z +c1be9b6a2c3e7741398621241be8ce1d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1814 + +exec-all.h +file + + + + +2013-08-23T00:54:48.000000Z +b2aefa957ea6d76c069943bcef725175 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +12249 + +softmmu_defs.h +file + + + + +2013-08-23T00:54:48.000000Z +747806f47d540ecb3d964e908fa851b5 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1100 + +qemu-lock.h +file + + + + +2013-08-23T00:54:48.000000Z +72768f0373ca26c827d3fb3823899062 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +6104 + +alpha.ld +file + + + + +2013-08-23T00:54:48.000000Z +356d81f8309c95a7e56030f159994620 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3984 + +microblaze-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +615754c2f376fa1fa5597c91764f1433 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +63528 + +configure-small +file + + + + +2013-08-23T00:54:48.000000Z +4bb671cbf53397bb0bb7610efcceb9dc +2010-04-24T23:27:43.537348Z +10 +datajerk +has-props + + + + + + + + + + + + + + + + + + + + +26399 + +create_config +file + + + + +2013-08-23T00:54:48.000000Z +6530e1a119eacfa791775814d5ef3fad +2010-04-24T23:27:43.537348Z +10 +datajerk +has-props + + + + + + + + + + + + + + + + + + + + +2185 + +softmmu_header.h +file + + + + +2013-08-23T00:54:48.000000Z +0743570baf66f809bf28d3d93b045f33 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4906 + +fpu +dir + +s390-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +438fa80f8e0460c709b874d10e9402b3 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +92323 + +def-helper.h +file + + + + +2013-08-23T00:54:48.000000Z +ec4e749da8ef73584514b61151a96912 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +6753 + +ioport.h +file + + + + +2013-08-23T00:54:48.000000Z +f8fb9c4d7259449b83e427e6b72c6582 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1852 + +sparc-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +3aabbc0a93f351579d983c66e2c442b2 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +174984 + +Makefile-small.objs +file + + + + +2013-08-23T00:54:48.000000Z +b03c1826045bdfa95e64b68d492876c0 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1167 + +ppc.ld +file + + + + +2013-08-23T00:54:48.000000Z +7e821f22aaea76f9c617f101645a8508 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8711 + +cpu-all.h +file + + + + +2013-08-23T00:54:48.000000Z +c07b0fe31b50188fcfc40e1878ec4af6 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +26756 + +m68k.ld +file + + + + +2013-08-23T00:54:48.000000Z +457ef814174b74c1b622006f0fcd9754 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +6013 + +hppa-dis.c +file + + + + +2013-08-23T00:54:48.000000Z +e68446691c95c67089ef60b06d684541 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +102545 + +i386.ld +file + + + + +2013-08-23T00:54:48.000000Z +1e10318c34a717ba6651e19e4842d3e7 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4553 + +targphys.h +file + + + + +2013-08-23T00:54:48.000000Z +c6d174a8fb45cc49e6d6c75ddfb74c7c +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +720 + +gdb-xml +dir + +host-utils.c +file + + + + +2013-08-23T00:54:48.000000Z +ffebafd4286b8a17081e2b99a056a80d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2887 + +cpu-defs.h +file + + + + +2013-08-23T00:54:48.000000Z +b4d86563d9f7af607eba807a58e7cf12 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8861 + +qemu-malloc.c +file + + + + +2013-08-23T00:54:48.000000Z +c57778e4b7e72cea4407828835364490 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2445 + +osdep.h +file + + + + +2013-08-23T00:54:48.000000Z +d78bc9c79cf6e57d5ed4bb10a2b31917 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2471 + +host-utils.h +file + + + + +2013-08-23T00:54:48.000000Z +a462eab831b2fe6e30d0e4649c17c411 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +5563 + +target-arm +dir + +sparc.ld +file + + + + +2013-08-23T00:54:48.000000Z +cdebceda4b5e17e89eb4f01dec70abff +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +4773 + +Makefile-small.target +file + + + + +2013-08-23T00:54:48.000000Z +687cfbc2c8f506316a8112416a3d1c6c +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2750 + diff --git a/qemu/qemu-git/.svn/prop-base/configure-small.svn-base b/qemu/qemu-git/.svn/prop-base/configure-small.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/qemu/qemu-git/.svn/prop-base/configure-small.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/qemu/qemu-git/.svn/prop-base/create_config.svn-base b/qemu/qemu-git/.svn/prop-base/create_config.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/qemu/qemu-git/.svn/prop-base/create_config.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/qemu/qemu-git/.svn/text-base/Makefile-small.hw.svn-base b/qemu/qemu-git/.svn/text-base/Makefile-small.hw.svn-base new file mode 100644 index 0000000..4a398cf --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/Makefile-small.hw.svn-base @@ -0,0 +1,25 @@ +# -*- Mode: makefile -*- +# Makefile for qemu target independent devices. + +include ../config-host.mak +include ../config-all-devices.mak +include config.mak +include $(SRC_PATH)/rules.mak + +.PHONY: all + +$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) + +QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu + +include $(SRC_PATH)/Makefile-small.objs + +all: $(hw-obj-y) +# Dummy command so that make thinks it has done something + @true + +clean: + rm -f *.o *.d *.a *~ + +# Include automatically generated dependency files +-include $(wildcard *.d */*.d) diff --git a/qemu/qemu-git/.svn/text-base/Makefile-small.objs.svn-base b/qemu/qemu-git/.svn/text-base/Makefile-small.objs.svn-base new file mode 100644 index 0000000..a2648a6 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/Makefile-small.objs.svn-base @@ -0,0 +1,32 @@ +# -*- Mode: makefile -*- + +####################################################################### +# block-obj-y is code used by both qemu system emulation and qemu-img + +block-obj-y = cache-utils.o module.o +block-obj-y += block.o aio.o aes.o osdep.o +block-obj-$(CONFIG_POSIX) += posix-aio-compat.o +block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o + +block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o +block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o +block-nested-y += parallels.o +block-nested-$(CONFIG_WIN32) += raw-win32.o +block-nested-$(CONFIG_POSIX) += raw-posix.o +block-nested-$(CONFIG_CURL) += curl.o + +block-obj-y += $(addprefix block/, $(block-nested-y)) + +###################################################################### +# libqemu_common.a: Target independent part of system emulation. The +# long term path is to suppress *all* target specific code in case of +# system emulation, i.e. a single QEMU executable should support all +# CPUs and machines. + +common-obj-y = cutils.o qemu-malloc.o + +#common-obj-y += $(block-obj-y) + +common-obj-y += tcg-runtime.o host-utils.o + +common-obj-$(CONFIG_COCOA) += cocoa.o diff --git a/qemu/qemu-git/.svn/text-base/Makefile-small.svn-base b/qemu/qemu-git/.svn/text-base/Makefile-small.svn-base new file mode 100644 index 0000000..a7e1dae --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/Makefile-small.svn-base @@ -0,0 +1,116 @@ +# -*- Mode: makefile -*- +# Makefile for QEMU. + +GENERATED_HEADERS = config-host.h + +ifneq ($(wildcard config-host.mak),) +# Put the all: rule here so that config-host.mak can contain dependencies. +all: build-all +include config-host.mak +include $(SRC_PATH)/rules.mak +config-host.mak: $(SRC_PATH)/configure-small + @echo $@ is out-of-date, running configure + @sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh +else +config-host.mak: + @echo "Please call configure before running make!" + @exit 1 +endif + +# Don't try to regenerate Makefile or configure +# We don't generate any of them +Makefile-small: ; +configure-small: ; + +.PHONY: all clean cscope distclean tar build-all + +$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) + +LIBS+=-lz + +SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) + +config-all-devices.mak: arm-softmmu/config-devices.mak + $(call quiet-command,cat arm-softmmu/config-devices.mak | grep =y | sort -u > $@," GEN $@") + +arm-softmmu/config-devices.mak: default-configs/arm-softmmu-small.mak + $(call quiet-command,cat $< > $@.tmp, " GEN $@") + @if test -f $@; then \ + if cmp -s $@.old $@ || cmp -s $@ $@.tmp; then \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ + else \ + if test -f $@.old; then \ + echo "WARNING: $@ (user modified) out of date.";\ + else \ + echo "WARNING: $@ out of date.";\ + fi; \ + echo "Run \"make defconfig\" to regenerate."; \ + rm $@.tmp; \ + fi; \ + else \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ + fi + +defconfig: + rm -f config-all-devices.mak arm-softmmu/config-devices.mak + +-include config-all-devices.mak + +build-all: subdir-arm-softmmu + +config-host.h: config-host.h-timestamp +config-host.h-timestamp: config-host.mak + +SUBDIR_RULES=subdir-arm-softmmu + +subdir-%: $(GENERATED_HEADERS) + $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) + +ifneq ($(wildcard config-host.mak),) +include $(SRC_PATH)/Makefile-small.objs +endif + +$(common-obj-y): $(GENERATED_HEADERS) +subdir-arm-softmmu: $(common-obj-y) + +###################################################################### + +$(block-obj-y): $(GENERATED_HEADERS) + +clean: + rm -f *.o *.d *.a TAGS cscope.* *~ */*~ + rm -f block/*.o block/*.d + for d in arm-softmmu libhw32 libhw64; do \ + if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ + done + +distclean: clean + rm -f config-host.mak config-host.h* config-host.ld + rm -f config-all-devices.mak + for d in arm-softmmu libhw32 libhw64; do \ + rm -rf $$d || exit 1 ; \ + done + +.PHONY: TAGS +TAGS: + find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags + +cscope: + rm -f ./cscope.* + find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files + cscope -b + +VERSION ?= $(shell cat VERSION) +FILE = qemu-$(VERSION) + +# tar release (use 'make -k tar' on a checkouted tree) +tar: + rm -rf /tmp/$(FILE) + cp -r . /tmp/$(FILE) + cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn + rm -rf /tmp/$(FILE) + +# Include automatically generated dependency files +-include $(wildcard *.d block/*.d) diff --git a/qemu/qemu-git/.svn/text-base/Makefile-small.target.svn-base b/qemu/qemu-git/.svn/text-base/Makefile-small.target.svn-base new file mode 100644 index 0000000..fe265d4 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/Makefile-small.target.svn-base @@ -0,0 +1,104 @@ +# -*- Mode: makefile -*- + +GENERATED_HEADERS = config-target.h + +include ../config-host.mak +include config-devices.mak +include config-target.mak +include $(SRC_PATH)/rules.mak +ifneq ($(HWDIR),) +include $(HWDIR)/config.mak +endif + +TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) +$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw) +QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H + +include $(SRC_PATH)/Makefile-small.objs + +# system emulator name +QEMU_PROG=qemu-system-arm$(EXESUF) + +PROGS=$(QEMU_PROG) + +LIBS+=-lm + +config-target.h: config-target.h-timestamp +config-target.h-timestamp: config-target.mak + +all: $(PROGS) + +# Dummy command so that make thinks it has done something + @true + +######################################################### +# cpu emulator library +libobj-y = exec.o translate-all.o cpu-exec.o translate.o +libobj-y += tcg/tcg.o +libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o +libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o +libobj-y += op_helper.o helper.o +libobj-$(CONFIG_NEED_MMU) += mmu.o +libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o + +# NOTE: the disassembler code is only needed for debugging +libobj-y += disas.o +libobj-$(CONFIG_ALPHA_DIS) += alpha-dis.o +libobj-$(CONFIG_ARM_DIS) += arm-dis.o +libobj-$(CONFIG_CRIS_DIS) += cris-dis.o +libobj-$(CONFIG_HPPA_DIS) += hppa-dis.o +libobj-$(CONFIG_I386_DIS) += i386-dis.o +libobj-$(CONFIG_M68K_DIS) += m68k-dis.o +libobj-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o +libobj-$(CONFIG_MIPS_DIS) += mips-dis.o +libobj-$(CONFIG_PPC_DIS) += ppc-dis.o +libobj-$(CONFIG_S390_DIS) += s390-dis.o +libobj-$(CONFIG_SH4_DIS) += sh4-dis.o +libobj-$(CONFIG_SPARC_DIS) += sparc-dis.o + +$(libobj-y): $(GENERATED_HEADERS) + +# libqemu + +translate.o: translate.c cpu.h + +translate-all.o: translate-all.c cpu.h + +tcg/tcg.o: cpu.h + +# HELPER_CFLAGS is used for all the code compiled with static register +# variables +op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + +######################################################### +# System emulator target +ifdef CONFIG_SOFTMMU + +#obj-y = gdbstub.o +LIBS+=-lz + +main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) + +$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) + +obj-y += $(addprefix ../, $(common-obj-y)) +obj-y += $(libobj-y) + +endif # CONFIG_SOFTMMU + +#obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o + +$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) +# $(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)) + + +gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh + $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") + +clean: + rm -f *.o *.a *~ $(PROGS) fpu/*.o + rm -f *.d */*.d tcg/*.o + rm -f gdbstub-xml.c + +# Include automatically generated dependency files +-include $(wildcard *.d */*.d) diff --git a/qemu/qemu-git/.svn/text-base/VERSION.svn-base b/qemu/qemu-git/.svn/text-base/VERSION.svn-base new file mode 100644 index 0000000..d9e30b8 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/VERSION.svn-base @@ -0,0 +1 @@ +0.12.50 diff --git a/qemu/qemu-git/.svn/text-base/alpha-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/alpha-dis.c.svn-base new file mode 100644 index 0000000..970da5b --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/alpha-dis.c.svn-base @@ -0,0 +1,1917 @@ +/* alpha-dis.c -- Disassemble Alpha AXP instructions + Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Richard Henderson , + patterned after the PPC opcode handling written by Ian Lance Taylor. + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, see +. */ + +#include +#include "dis-asm.h" + +/* The opcode table is an array of struct alpha_opcode. */ + +struct alpha_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned mask; + + /* One bit flags for the opcode. These are primarily used to + indicate specific processors and environments support the + instructions. The defined values are listed below. */ + unsigned flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[4]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct alpha_opcode alpha_opcodes[]; +extern const unsigned alpha_num_opcodes; + +/* Values defined for the flags field of a struct alpha_opcode. */ + +/* CPU Availability */ +#define AXP_OPCODE_BASE 0x0001 /* Base architecture -- all cpus. */ +#define AXP_OPCODE_EV4 0x0002 /* EV4 specific PALcode insns. */ +#define AXP_OPCODE_EV5 0x0004 /* EV5 specific PALcode insns. */ +#define AXP_OPCODE_EV6 0x0008 /* EV6 specific PALcode insns. */ +#define AXP_OPCODE_BWX 0x0100 /* Byte/word extension (amask bit 0). */ +#define AXP_OPCODE_CIX 0x0200 /* "Count" extension (amask bit 1). */ +#define AXP_OPCODE_MAX 0x0400 /* Multimedia extension (amask bit 8). */ + +#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6)) + +/* A macro to extract the major opcode from an instruction. */ +#define AXP_OP(i) (((i) >> 26) & 0x3F) + +/* The total number of major opcodes. */ +#define AXP_NOPS 0x40 + + +/* The operands table is an array of struct alpha_operand. */ + +struct alpha_operand +{ + /* The number of bits in the operand. */ + unsigned int bits : 5; + + /* How far the operand is left shifted in the instruction. */ + unsigned int shift : 5; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* One bit syntax flags. */ + unsigned int flags : 16; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned (*insert) (unsigned instruction, int op, + const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & AXP_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + int (*extract) (unsigned instruction, int *invalid); +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the alpha_opcodes table. */ + +extern const struct alpha_operand alpha_operands[]; +extern const unsigned alpha_num_operands; + +/* Values defined for the flags field of a struct alpha_operand. */ + +/* Mask for selecting the type for typecheck purposes */ +#define AXP_OPERAND_TYPECHECK_MASK \ + (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \ + AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \ + AXP_OPERAND_UNSIGNED) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics, for which two operands fields + are identical. The assembler should call the insert function with + any op value. The disassembler should call the extract function, + ignore the return value, and check the value placed in the invalid + argument. */ +#define AXP_OPERAND_FAKE 01 + +/* The operand should be wrapped in parentheses rather than separated + from the previous by a comma. This is used for the load and store + instructions which want their operands to look like "Ra,disp(Rb)". */ +#define AXP_OPERAND_PARENS 02 + +/* Used in combination with PARENS, this suppresses the suppression of + the comma. This is used for "jmp Ra,(Rb),hint". */ +#define AXP_OPERAND_COMMA 04 + +/* This operand names an integer register. */ +#define AXP_OPERAND_IR 010 + +/* This operand names a floating point register. */ +#define AXP_OPERAND_FPR 020 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define AXP_OPERAND_RELATIVE 040 + +/* This operand takes signed values. */ +#define AXP_OPERAND_SIGNED 0100 + +/* This operand takes unsigned values. This exists primarily so that + a flags value of 0 can be treated as end-of-arguments. */ +#define AXP_OPERAND_UNSIGNED 0200 + +/* Suppress overflow detection on this field. This is used for hints. */ +#define AXP_OPERAND_NOOVERFLOW 0400 + +/* Mask for optional argument default value. */ +#define AXP_OPERAND_OPTIONAL_MASK 07000 + +/* This operand defaults to zero. This is used for jump hints. */ +#define AXP_OPERAND_DEFAULT_ZERO 01000 + +/* This operand should default to the first (real) operand and is used + in conjunction with AXP_OPERAND_OPTIONAL. This allows + "and $0,3,$0" to be written as "and $0,3", etc. I don't like + it, but it's what DEC does. */ +#define AXP_OPERAND_DEFAULT_FIRST 02000 + +/* Similarly, this operand should default to the second (real) operand. + This allows "negl $0" instead of "negl $0,$0". */ +#define AXP_OPERAND_DEFAULT_SECOND 04000 + + +/* Register common names */ + +#define AXP_REG_V0 0 +#define AXP_REG_T0 1 +#define AXP_REG_T1 2 +#define AXP_REG_T2 3 +#define AXP_REG_T3 4 +#define AXP_REG_T4 5 +#define AXP_REG_T5 6 +#define AXP_REG_T6 7 +#define AXP_REG_T7 8 +#define AXP_REG_S0 9 +#define AXP_REG_S1 10 +#define AXP_REG_S2 11 +#define AXP_REG_S3 12 +#define AXP_REG_S4 13 +#define AXP_REG_S5 14 +#define AXP_REG_FP 15 +#define AXP_REG_A0 16 +#define AXP_REG_A1 17 +#define AXP_REG_A2 18 +#define AXP_REG_A3 19 +#define AXP_REG_A4 20 +#define AXP_REG_A5 21 +#define AXP_REG_T8 22 +#define AXP_REG_T9 23 +#define AXP_REG_T10 24 +#define AXP_REG_T11 25 +#define AXP_REG_RA 26 +#define AXP_REG_PV 27 +#define AXP_REG_T12 27 +#define AXP_REG_AT 28 +#define AXP_REG_GP 29 +#define AXP_REG_SP 30 +#define AXP_REG_ZERO 31 + +#define bfd_mach_alpha_ev4 0x10 +#define bfd_mach_alpha_ev5 0x20 +#define bfd_mach_alpha_ev6 0x30 + +enum bfd_reloc_code_real { + BFD_RELOC_23_PCREL_S2, + BFD_RELOC_ALPHA_HINT +}; + +/* This file holds the Alpha AXP opcode table. The opcode table includes + almost all of the extended instruction mnemonics. This permits the + disassembler to use them, and simplifies the assembler logic, at the + cost of increasing the table size. The table is strictly constant + data, so the compiler should be able to put it in the text segment. + + This file also holds the operand table. All knowledge about inserting + and extracting operands from instructions is kept in this file. + + The information for the base instruction set was compiled from the + _Alpha Architecture Handbook_, Digital Order Number EC-QD2KB-TE, + version 2. + + The information for the post-ev5 architecture extensions BWX, CIX and + MAX came from version 3 of this same document, which is also available + on-line at http://ftp.digital.com/pub/Digital/info/semiconductor + /literature/alphahb2.pdf + + The information for the EV4 PALcode instructions was compiled from + _DECchip 21064 and DECchip 21064A Alpha AXP Microprocessors Hardware + Reference Manual_, Digital Order Number EC-Q9ZUA-TE, preliminary + revision dated June 1994. + + The information for the EV5 PALcode instructions was compiled from + _Alpha 21164 Microprocessor Hardware Reference Manual_, Digital + Order Number EC-QAEQB-TE, preliminary revision dated April 1995. */ + +/* Local insertion and extraction functions */ + +static unsigned insert_rba (unsigned, int, const char **); +static unsigned insert_rca (unsigned, int, const char **); +static unsigned insert_za (unsigned, int, const char **); +static unsigned insert_zb (unsigned, int, const char **); +static unsigned insert_zc (unsigned, int, const char **); +static unsigned insert_bdisp (unsigned, int, const char **); +static unsigned insert_jhint (unsigned, int, const char **); +static unsigned insert_ev6hwjhint (unsigned, int, const char **); + +static int extract_rba (unsigned, int *); +static int extract_rca (unsigned, int *); +static int extract_za (unsigned, int *); +static int extract_zb (unsigned, int *); +static int extract_zc (unsigned, int *); +static int extract_bdisp (unsigned, int *); +static int extract_jhint (unsigned, int *); +static int extract_ev6hwjhint (unsigned, int *); + + +/* The operands table */ + +const struct alpha_operand alpha_operands[] = +{ + /* The fields are bits, shift, insert, extract, flags */ + /* The zero index is used to indicate end-of-list */ +#define UNUSED 0 + { 0, 0, 0, 0, 0, 0 }, + + /* The plain integer register fields */ +#define RA (UNUSED + 1) + { 5, 21, 0, AXP_OPERAND_IR, 0, 0 }, +#define RB (RA + 1) + { 5, 16, 0, AXP_OPERAND_IR, 0, 0 }, +#define RC (RB + 1) + { 5, 0, 0, AXP_OPERAND_IR, 0, 0 }, + + /* The plain fp register fields */ +#define FA (RC + 1) + { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FB (FA + 1) + { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FC (FB + 1) + { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 }, + + /* The integer registers when they are ZERO */ +#define ZA (FC + 1) + { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za }, +#define ZB (ZA + 1) + { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb }, +#define ZC (ZB + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc }, + + /* The RB field when it needs parentheses */ +#define PRB (ZC + 1) + { 5, 16, 0, AXP_OPERAND_IR|AXP_OPERAND_PARENS, 0, 0 }, + + /* The RB field when it needs parentheses _and_ a preceding comma */ +#define CPRB (PRB + 1) + { 5, 16, 0, + AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA, 0, 0 }, + + /* The RB field when it must be the same as the RA field */ +#define RBA (CPRB + 1) + { 5, 16, 0, AXP_OPERAND_FAKE, insert_rba, extract_rba }, + + /* The RC field when it must be the same as the RB field */ +#define RCA (RBA + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_rca, extract_rca }, + + /* The RC field when it can *default* to RA */ +#define DRC1 (RCA + 1) + { 5, 0, 0, + AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The RC field when it can *default* to RB */ +#define DRC2 (DRC1 + 1) + { 5, 0, 0, + AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The FC field when it can *default* to RA */ +#define DFC1 (DRC2 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The FC field when it can *default* to RB */ +#define DFC2 (DFC1 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The unsigned 8-bit literal of Operate format insns */ +#define LIT (DFC2 + 1) + { 8, 13, -LIT, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The signed 16-bit displacement of Memory format insns. From here + we can't tell what relocation should be used, so don't use a default. */ +#define MDISP (LIT + 1) + { 16, 0, -MDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The signed "23-bit" aligned displacement of Branch format insns */ +#define BDISP (MDISP + 1) + { 21, 0, BFD_RELOC_23_PCREL_S2, + AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, + + /* The 26-bit PALcode function */ +#define PALFN (BDISP + 1) + { 26, 0, -PALFN, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint */ +#define JMPHINT (PALFN + 1) + { 14, 0, BFD_RELOC_ALPHA_HINT, + AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW, + insert_jhint, extract_jhint }, + + /* The optional hint to RET/JSR_COROUTINE */ +#define RETHINT (JMPHINT + 1) + { 14, 0, -RETHINT, + AXP_OPERAND_UNSIGNED|AXP_OPERAND_DEFAULT_ZERO, 0, 0 }, + + /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns */ +#define EV4HWDISP (RETHINT + 1) +#define EV6HWDISP (EV4HWDISP) + { 12, 0, -EV4HWDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The 5-bit index for the ev4 hw_m[ft]pr (pal19/pal1d) insns */ +#define EV4HWINDEX (EV4HWDISP + 1) + { 5, 0, -EV4HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 8-bit index for the oddly unqualified hw_m[tf]pr insns + that occur in DEC PALcode. */ +#define EV4EXTHWINDEX (EV4HWINDEX + 1) + { 8, 0, -EV4EXTHWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 10-bit displacement for the ev5 hw_{ld,st} (pal1b/pal1f) insns */ +#define EV5HWDISP (EV4EXTHWINDEX + 1) + { 10, 0, -EV5HWDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The 16-bit index for the ev5 hw_m[ft]pr (pal19/pal1d) insns */ +#define EV5HWINDEX (EV5HWDISP + 1) + { 16, 0, -EV5HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 16-bit combined index/scoreboard mask for the ev6 + hw_m[ft]pr (pal19/pal1d) insns */ +#define EV6HWINDEX (EV5HWINDEX + 1) + { 16, 0, -EV6HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn */ +#define EV6HWJMPHINT (EV6HWINDEX+ 1) + { 8, 0, -EV6HWJMPHINT, + AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW, + insert_ev6hwjhint, extract_ev6hwjhint } +}; + +const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operands); + +/* The RB field when it is the same as the RA field in the same insn. + This operand is marked fake. The insertion function just copies + the RA field into the RB field, and the extraction function just + checks that the fields are the same. */ + +/*ARGSUSED*/ +static unsigned +insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static int +extract_rba(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + + +/* The same for the RC field */ + +/*ARGSUSED*/ +static unsigned +insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((insn >> 21) & 0x1f); +} + +static int +extract_rca(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != (insn & 0x1f)) + *invalid = 1; + return 0; +} + + +/* Fake arguments in which the registers must be set to ZERO */ + +/*ARGSUSED*/ +static unsigned +insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 21); +} + +static int +extract_za(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +/*ARGSUSED*/ +static unsigned +insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 16); +} + +static int +extract_zb(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +/*ARGSUSED*/ +static unsigned +insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | 31; +} + +static int +extract_zc(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && (insn & 0x1f) != 31) + *invalid = 1; + return 0; +} + + +/* The displacement field of a Branch format insn. */ + +static unsigned +insert_bdisp(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("branch operand unaligned"); + return insn | ((value / 4) & 0x1FFFFF); +} + +/*ARGSUSED*/ +static int +extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); +} + + +/* The hint field of a JMP/JSR insn. */ + +static unsigned +insert_jhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("jump hint unaligned"); + return insn | ((value / 4) & 0x3FFF); +} + +/*ARGSUSED*/ +static int +extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000); +} + +/* The hint field of an EV6 HW_JMP/JSR insn. */ + +static unsigned +insert_ev6hwjhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("jump hint unaligned"); + return insn | ((value / 4) & 0x1FFF); +} + +/*ARGSUSED*/ +static int +extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); +} + + +/* Macros used to form opcodes */ + +/* The main opcode */ +#define OP(x) (((x) & 0x3F) << 26) +#define OP_MASK 0xFC000000 + +/* Branch format instructions */ +#define BRA_(oo) OP(oo) +#define BRA_MASK OP_MASK +#define BRA(oo) BRA_(oo), BRA_MASK + +/* Floating point format instructions */ +#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5)) +#define FP_MASK (OP_MASK | 0xFFE0) +#define FP(oo,fff) FP_(oo,fff), FP_MASK + +/* Memory format instructions */ +#define MEM_(oo) OP(oo) +#define MEM_MASK OP_MASK +#define MEM(oo) MEM_(oo), MEM_MASK + +/* Memory/Func Code format instructions */ +#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF)) +#define MFC_MASK (OP_MASK | 0xFFFF) +#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK + +/* Memory/Branch format instructions */ +#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14)) +#define MBR_MASK (OP_MASK | 0xC000) +#define MBR(oo,h) MBR_(oo,h), MBR_MASK + +/* Operate format instructions. The OPRL variant specifies a + literal second argument. */ +#define OPR_(oo,ff) (OP(oo) | (((ff) & 0x7F) << 5)) +#define OPRL_(oo,ff) (OPR_((oo),(ff)) | 0x1000) +#define OPR_MASK (OP_MASK | 0x1FE0) +#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK +#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK + +/* Generic PALcode format instructions */ +#define PCD_(oo) OP(oo) +#define PCD_MASK OP_MASK +#define PCD(oo) PCD_(oo), PCD_MASK + +/* Specific PALcode instructions */ +#define SPCD_(oo,ffff) (OP(oo) | ((ffff) & 0x3FFFFFF)) +#define SPCD_MASK 0xFFFFFFFF +#define SPCD(oo,ffff) SPCD_(oo,ffff), SPCD_MASK + +/* Hardware memory (hw_{ld,st}) instructions */ +#define EV4HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) +#define EV4HWMEM_MASK (OP_MASK | 0xF000) +#define EV4HWMEM(oo,f) EV4HWMEM_(oo,f), EV4HWMEM_MASK + +#define EV5HWMEM_(oo,f) (OP(oo) | (((f) & 0x3F) << 10)) +#define EV5HWMEM_MASK (OP_MASK | 0xF800) +#define EV5HWMEM(oo,f) EV5HWMEM_(oo,f), EV5HWMEM_MASK + +#define EV6HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) +#define EV6HWMEM_MASK (OP_MASK | 0xF000) +#define EV6HWMEM(oo,f) EV6HWMEM_(oo,f), EV6HWMEM_MASK + +#define EV6HWMBR_(oo,h) (OP(oo) | (((h) & 7) << 13)) +#define EV6HWMBR_MASK (OP_MASK | 0xE000) +#define EV6HWMBR(oo,h) EV6HWMBR_(oo,h), EV6HWMBR_MASK + +/* Abbreviations for instruction subsets. */ +#define BASE AXP_OPCODE_BASE +#define EV4 AXP_OPCODE_EV4 +#define EV5 AXP_OPCODE_EV5 +#define EV6 AXP_OPCODE_EV6 +#define BWX AXP_OPCODE_BWX +#define CIX AXP_OPCODE_CIX +#define MAX AXP_OPCODE_MAX + +/* Common combinations of arguments */ +#define ARG_NONE { 0 } +#define ARG_BRA { RA, BDISP } +#define ARG_FBRA { FA, BDISP } +#define ARG_FP { FA, FB, DFC1 } +#define ARG_FPZ1 { ZA, FB, DFC1 } +#define ARG_MEM { RA, MDISP, PRB } +#define ARG_FMEM { FA, MDISP, PRB } +#define ARG_OPR { RA, RB, DRC1 } +#define ARG_OPRL { RA, LIT, DRC1 } +#define ARG_OPRZ1 { ZA, RB, DRC1 } +#define ARG_OPRLZ1 { ZA, LIT, RC } +#define ARG_PCD { PALFN } +#define ARG_EV4HWMEM { RA, EV4HWDISP, PRB } +#define ARG_EV4HWMPR { RA, RBA, EV4HWINDEX } +#define ARG_EV5HWMEM { RA, EV5HWDISP, PRB } +#define ARG_EV6HWMEM { RA, EV6HWDISP, PRB } + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK { OPERANDS } + + NAME is the name of the instruction. + + OPCODE is the instruction opcode. + + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + + OPERANDS is the list of operands. + + The preceding macros merge the text of the OPCODE and MASK fields. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. + + Otherwise, it is sorted by major opcode and minor function code. + + There are three classes of not-really-instructions in this table: + + ALIAS is another name for another instruction. Some of + these come from the Architecture Handbook, some + come from the original gas opcode tables. In all + cases, the functionality of the opcode is unchanged. + + PSEUDO a stylized code form endorsed by Chapter A.4 of the + Architecture Handbook. + + EXTRA a stylized code form found in the original gas tables. + + And two annotations: + + EV56 BUT opcodes that are officially introduced as of the ev56, + but with defined results on previous implementations. + + EV56 UNA opcodes that were introduced as of the ev56 with + presumably undefined results on previous implementations + that were not assigned to a particular extension. +*/ + +const struct alpha_opcode alpha_opcodes[] = { + { "halt", SPCD(0x00,0x0000), BASE, ARG_NONE }, + { "draina", SPCD(0x00,0x0002), BASE, ARG_NONE }, + { "bpt", SPCD(0x00,0x0080), BASE, ARG_NONE }, + { "bugchk", SPCD(0x00,0x0081), BASE, ARG_NONE }, + { "callsys", SPCD(0x00,0x0083), BASE, ARG_NONE }, + { "chmk", SPCD(0x00,0x0083), BASE, ARG_NONE }, + { "imb", SPCD(0x00,0x0086), BASE, ARG_NONE }, + { "rduniq", SPCD(0x00,0x009e), BASE, ARG_NONE }, + { "wruniq", SPCD(0x00,0x009f), BASE, ARG_NONE }, + { "gentrap", SPCD(0x00,0x00aa), BASE, ARG_NONE }, + { "call_pal", PCD(0x00), BASE, ARG_PCD }, + { "pal", PCD(0x00), BASE, ARG_PCD }, /* alias */ + + { "lda", MEM(0x08), BASE, { RA, MDISP, ZB } }, /* pseudo */ + { "lda", MEM(0x08), BASE, ARG_MEM }, + { "ldah", MEM(0x09), BASE, { RA, MDISP, ZB } }, /* pseudo */ + { "ldah", MEM(0x09), BASE, ARG_MEM }, + { "ldbu", MEM(0x0A), BWX, ARG_MEM }, + { "unop", MEM_(0x0B) | (30 << 16), + MEM_MASK, BASE, { ZA } }, /* pseudo */ + { "ldq_u", MEM(0x0B), BASE, ARG_MEM }, + { "ldwu", MEM(0x0C), BWX, ARG_MEM }, + { "stw", MEM(0x0D), BWX, ARG_MEM }, + { "stb", MEM(0x0E), BWX, ARG_MEM }, + { "stq_u", MEM(0x0F), BASE, ARG_MEM }, + + { "sextl", OPR(0x10,0x00), BASE, ARG_OPRZ1 }, /* pseudo */ + { "sextl", OPRL(0x10,0x00), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "addl", OPR(0x10,0x00), BASE, ARG_OPR }, + { "addl", OPRL(0x10,0x00), BASE, ARG_OPRL }, + { "s4addl", OPR(0x10,0x02), BASE, ARG_OPR }, + { "s4addl", OPRL(0x10,0x02), BASE, ARG_OPRL }, + { "negl", OPR(0x10,0x09), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negl", OPRL(0x10,0x09), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subl", OPR(0x10,0x09), BASE, ARG_OPR }, + { "subl", OPRL(0x10,0x09), BASE, ARG_OPRL }, + { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR }, + { "s4subl", OPRL(0x10,0x0B), BASE, ARG_OPRL }, + { "cmpbge", OPR(0x10,0x0F), BASE, ARG_OPR }, + { "cmpbge", OPRL(0x10,0x0F), BASE, ARG_OPRL }, + { "s8addl", OPR(0x10,0x12), BASE, ARG_OPR }, + { "s8addl", OPRL(0x10,0x12), BASE, ARG_OPRL }, + { "s8subl", OPR(0x10,0x1B), BASE, ARG_OPR }, + { "s8subl", OPRL(0x10,0x1B), BASE, ARG_OPRL }, + { "cmpult", OPR(0x10,0x1D), BASE, ARG_OPR }, + { "cmpult", OPRL(0x10,0x1D), BASE, ARG_OPRL }, + { "addq", OPR(0x10,0x20), BASE, ARG_OPR }, + { "addq", OPRL(0x10,0x20), BASE, ARG_OPRL }, + { "s4addq", OPR(0x10,0x22), BASE, ARG_OPR }, + { "s4addq", OPRL(0x10,0x22), BASE, ARG_OPRL }, + { "negq", OPR(0x10,0x29), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negq", OPRL(0x10,0x29), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subq", OPR(0x10,0x29), BASE, ARG_OPR }, + { "subq", OPRL(0x10,0x29), BASE, ARG_OPRL }, + { "s4subq", OPR(0x10,0x2B), BASE, ARG_OPR }, + { "s4subq", OPRL(0x10,0x2B), BASE, ARG_OPRL }, + { "cmpeq", OPR(0x10,0x2D), BASE, ARG_OPR }, + { "cmpeq", OPRL(0x10,0x2D), BASE, ARG_OPRL }, + { "s8addq", OPR(0x10,0x32), BASE, ARG_OPR }, + { "s8addq", OPRL(0x10,0x32), BASE, ARG_OPRL }, + { "s8subq", OPR(0x10,0x3B), BASE, ARG_OPR }, + { "s8subq", OPRL(0x10,0x3B), BASE, ARG_OPRL }, + { "cmpule", OPR(0x10,0x3D), BASE, ARG_OPR }, + { "cmpule", OPRL(0x10,0x3D), BASE, ARG_OPRL }, + { "addl/v", OPR(0x10,0x40), BASE, ARG_OPR }, + { "addl/v", OPRL(0x10,0x40), BASE, ARG_OPRL }, + { "negl/v", OPR(0x10,0x49), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negl/v", OPRL(0x10,0x49), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subl/v", OPR(0x10,0x49), BASE, ARG_OPR }, + { "subl/v", OPRL(0x10,0x49), BASE, ARG_OPRL }, + { "cmplt", OPR(0x10,0x4D), BASE, ARG_OPR }, + { "cmplt", OPRL(0x10,0x4D), BASE, ARG_OPRL }, + { "addq/v", OPR(0x10,0x60), BASE, ARG_OPR }, + { "addq/v", OPRL(0x10,0x60), BASE, ARG_OPRL }, + { "negq/v", OPR(0x10,0x69), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negq/v", OPRL(0x10,0x69), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subq/v", OPR(0x10,0x69), BASE, ARG_OPR }, + { "subq/v", OPRL(0x10,0x69), BASE, ARG_OPRL }, + { "cmple", OPR(0x10,0x6D), BASE, ARG_OPR }, + { "cmple", OPRL(0x10,0x6D), BASE, ARG_OPRL }, + + { "and", OPR(0x11,0x00), BASE, ARG_OPR }, + { "and", OPRL(0x11,0x00), BASE, ARG_OPRL }, + { "andnot", OPR(0x11,0x08), BASE, ARG_OPR }, /* alias */ + { "andnot", OPRL(0x11,0x08), BASE, ARG_OPRL }, /* alias */ + { "bic", OPR(0x11,0x08), BASE, ARG_OPR }, + { "bic", OPRL(0x11,0x08), BASE, ARG_OPRL }, + { "cmovlbs", OPR(0x11,0x14), BASE, ARG_OPR }, + { "cmovlbs", OPRL(0x11,0x14), BASE, ARG_OPRL }, + { "cmovlbc", OPR(0x11,0x16), BASE, ARG_OPR }, + { "cmovlbc", OPRL(0x11,0x16), BASE, ARG_OPRL }, + { "nop", OPR(0x11,0x20), BASE, { ZA, ZB, ZC } }, /* pseudo */ + { "clr", OPR(0x11,0x20), BASE, { ZA, ZB, RC } }, /* pseudo */ + { "mov", OPR(0x11,0x20), BASE, { ZA, RB, RC } }, /* pseudo */ + { "mov", OPR(0x11,0x20), BASE, { RA, RBA, RC } }, /* pseudo */ + { "mov", OPRL(0x11,0x20), BASE, { ZA, LIT, RC } }, /* pseudo */ + { "or", OPR(0x11,0x20), BASE, ARG_OPR }, /* alias */ + { "or", OPRL(0x11,0x20), BASE, ARG_OPRL }, /* alias */ + { "bis", OPR(0x11,0x20), BASE, ARG_OPR }, + { "bis", OPRL(0x11,0x20), BASE, ARG_OPRL }, + { "cmoveq", OPR(0x11,0x24), BASE, ARG_OPR }, + { "cmoveq", OPRL(0x11,0x24), BASE, ARG_OPRL }, + { "cmovne", OPR(0x11,0x26), BASE, ARG_OPR }, + { "cmovne", OPRL(0x11,0x26), BASE, ARG_OPRL }, + { "not", OPR(0x11,0x28), BASE, ARG_OPRZ1 }, /* pseudo */ + { "not", OPRL(0x11,0x28), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "ornot", OPR(0x11,0x28), BASE, ARG_OPR }, + { "ornot", OPRL(0x11,0x28), BASE, ARG_OPRL }, + { "xor", OPR(0x11,0x40), BASE, ARG_OPR }, + { "xor", OPRL(0x11,0x40), BASE, ARG_OPRL }, + { "cmovlt", OPR(0x11,0x44), BASE, ARG_OPR }, + { "cmovlt", OPRL(0x11,0x44), BASE, ARG_OPRL }, + { "cmovge", OPR(0x11,0x46), BASE, ARG_OPR }, + { "cmovge", OPRL(0x11,0x46), BASE, ARG_OPRL }, + { "eqv", OPR(0x11,0x48), BASE, ARG_OPR }, + { "eqv", OPRL(0x11,0x48), BASE, ARG_OPRL }, + { "xornot", OPR(0x11,0x48), BASE, ARG_OPR }, /* alias */ + { "xornot", OPRL(0x11,0x48), BASE, ARG_OPRL }, /* alias */ + { "amask", OPR(0x11,0x61), BASE, ARG_OPRZ1 }, /* ev56 but */ + { "amask", OPRL(0x11,0x61), BASE, ARG_OPRLZ1 }, /* ev56 but */ + { "cmovle", OPR(0x11,0x64), BASE, ARG_OPR }, + { "cmovle", OPRL(0x11,0x64), BASE, ARG_OPRL }, + { "cmovgt", OPR(0x11,0x66), BASE, ARG_OPR }, + { "cmovgt", OPRL(0x11,0x66), BASE, ARG_OPRL }, + { "implver", OPRL_(0x11,0x6C)|(31<<21)|(1<<13), + 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */ + + { "mskbl", OPR(0x12,0x02), BASE, ARG_OPR }, + { "mskbl", OPRL(0x12,0x02), BASE, ARG_OPRL }, + { "extbl", OPR(0x12,0x06), BASE, ARG_OPR }, + { "extbl", OPRL(0x12,0x06), BASE, ARG_OPRL }, + { "insbl", OPR(0x12,0x0B), BASE, ARG_OPR }, + { "insbl", OPRL(0x12,0x0B), BASE, ARG_OPRL }, + { "mskwl", OPR(0x12,0x12), BASE, ARG_OPR }, + { "mskwl", OPRL(0x12,0x12), BASE, ARG_OPRL }, + { "extwl", OPR(0x12,0x16), BASE, ARG_OPR }, + { "extwl", OPRL(0x12,0x16), BASE, ARG_OPRL }, + { "inswl", OPR(0x12,0x1B), BASE, ARG_OPR }, + { "inswl", OPRL(0x12,0x1B), BASE, ARG_OPRL }, + { "mskll", OPR(0x12,0x22), BASE, ARG_OPR }, + { "mskll", OPRL(0x12,0x22), BASE, ARG_OPRL }, + { "extll", OPR(0x12,0x26), BASE, ARG_OPR }, + { "extll", OPRL(0x12,0x26), BASE, ARG_OPRL }, + { "insll", OPR(0x12,0x2B), BASE, ARG_OPR }, + { "insll", OPRL(0x12,0x2B), BASE, ARG_OPRL }, + { "zap", OPR(0x12,0x30), BASE, ARG_OPR }, + { "zap", OPRL(0x12,0x30), BASE, ARG_OPRL }, + { "zapnot", OPR(0x12,0x31), BASE, ARG_OPR }, + { "zapnot", OPRL(0x12,0x31), BASE, ARG_OPRL }, + { "mskql", OPR(0x12,0x32), BASE, ARG_OPR }, + { "mskql", OPRL(0x12,0x32), BASE, ARG_OPRL }, + { "srl", OPR(0x12,0x34), BASE, ARG_OPR }, + { "srl", OPRL(0x12,0x34), BASE, ARG_OPRL }, + { "extql", OPR(0x12,0x36), BASE, ARG_OPR }, + { "extql", OPRL(0x12,0x36), BASE, ARG_OPRL }, + { "sll", OPR(0x12,0x39), BASE, ARG_OPR }, + { "sll", OPRL(0x12,0x39), BASE, ARG_OPRL }, + { "insql", OPR(0x12,0x3B), BASE, ARG_OPR }, + { "insql", OPRL(0x12,0x3B), BASE, ARG_OPRL }, + { "sra", OPR(0x12,0x3C), BASE, ARG_OPR }, + { "sra", OPRL(0x12,0x3C), BASE, ARG_OPRL }, + { "mskwh", OPR(0x12,0x52), BASE, ARG_OPR }, + { "mskwh", OPRL(0x12,0x52), BASE, ARG_OPRL }, + { "inswh", OPR(0x12,0x57), BASE, ARG_OPR }, + { "inswh", OPRL(0x12,0x57), BASE, ARG_OPRL }, + { "extwh", OPR(0x12,0x5A), BASE, ARG_OPR }, + { "extwh", OPRL(0x12,0x5A), BASE, ARG_OPRL }, + { "msklh", OPR(0x12,0x62), BASE, ARG_OPR }, + { "msklh", OPRL(0x12,0x62), BASE, ARG_OPRL }, + { "inslh", OPR(0x12,0x67), BASE, ARG_OPR }, + { "inslh", OPRL(0x12,0x67), BASE, ARG_OPRL }, + { "extlh", OPR(0x12,0x6A), BASE, ARG_OPR }, + { "extlh", OPRL(0x12,0x6A), BASE, ARG_OPRL }, + { "mskqh", OPR(0x12,0x72), BASE, ARG_OPR }, + { "mskqh", OPRL(0x12,0x72), BASE, ARG_OPRL }, + { "insqh", OPR(0x12,0x77), BASE, ARG_OPR }, + { "insqh", OPRL(0x12,0x77), BASE, ARG_OPRL }, + { "extqh", OPR(0x12,0x7A), BASE, ARG_OPR }, + { "extqh", OPRL(0x12,0x7A), BASE, ARG_OPRL }, + + { "mull", OPR(0x13,0x00), BASE, ARG_OPR }, + { "mull", OPRL(0x13,0x00), BASE, ARG_OPRL }, + { "mulq", OPR(0x13,0x20), BASE, ARG_OPR }, + { "mulq", OPRL(0x13,0x20), BASE, ARG_OPRL }, + { "umulh", OPR(0x13,0x30), BASE, ARG_OPR }, + { "umulh", OPRL(0x13,0x30), BASE, ARG_OPRL }, + { "mull/v", OPR(0x13,0x40), BASE, ARG_OPR }, + { "mull/v", OPRL(0x13,0x40), BASE, ARG_OPRL }, + { "mulq/v", OPR(0x13,0x60), BASE, ARG_OPR }, + { "mulq/v", OPRL(0x13,0x60), BASE, ARG_OPRL }, + + { "itofs", FP(0x14,0x004), CIX, { RA, ZB, FC } }, + { "sqrtf/c", FP(0x14,0x00A), CIX, ARG_FPZ1 }, + { "sqrts/c", FP(0x14,0x00B), CIX, ARG_FPZ1 }, + { "itoff", FP(0x14,0x014), CIX, { RA, ZB, FC } }, + { "itoft", FP(0x14,0x024), CIX, { RA, ZB, FC } }, + { "sqrtg/c", FP(0x14,0x02A), CIX, ARG_FPZ1 }, + { "sqrtt/c", FP(0x14,0x02B), CIX, ARG_FPZ1 }, + { "sqrts/m", FP(0x14,0x04B), CIX, ARG_FPZ1 }, + { "sqrtt/m", FP(0x14,0x06B), CIX, ARG_FPZ1 }, + { "sqrtf", FP(0x14,0x08A), CIX, ARG_FPZ1 }, + { "sqrts", FP(0x14,0x08B), CIX, ARG_FPZ1 }, + { "sqrtg", FP(0x14,0x0AA), CIX, ARG_FPZ1 }, + { "sqrtt", FP(0x14,0x0AB), CIX, ARG_FPZ1 }, + { "sqrts/d", FP(0x14,0x0CB), CIX, ARG_FPZ1 }, + { "sqrtt/d", FP(0x14,0x0EB), CIX, ARG_FPZ1 }, + { "sqrtf/uc", FP(0x14,0x10A), CIX, ARG_FPZ1 }, + { "sqrts/uc", FP(0x14,0x10B), CIX, ARG_FPZ1 }, + { "sqrtg/uc", FP(0x14,0x12A), CIX, ARG_FPZ1 }, + { "sqrtt/uc", FP(0x14,0x12B), CIX, ARG_FPZ1 }, + { "sqrts/um", FP(0x14,0x14B), CIX, ARG_FPZ1 }, + { "sqrtt/um", FP(0x14,0x16B), CIX, ARG_FPZ1 }, + { "sqrtf/u", FP(0x14,0x18A), CIX, ARG_FPZ1 }, + { "sqrts/u", FP(0x14,0x18B), CIX, ARG_FPZ1 }, + { "sqrtg/u", FP(0x14,0x1AA), CIX, ARG_FPZ1 }, + { "sqrtt/u", FP(0x14,0x1AB), CIX, ARG_FPZ1 }, + { "sqrts/ud", FP(0x14,0x1CB), CIX, ARG_FPZ1 }, + { "sqrtt/ud", FP(0x14,0x1EB), CIX, ARG_FPZ1 }, + { "sqrtf/sc", FP(0x14,0x40A), CIX, ARG_FPZ1 }, + { "sqrtg/sc", FP(0x14,0x42A), CIX, ARG_FPZ1 }, + { "sqrtf/s", FP(0x14,0x48A), CIX, ARG_FPZ1 }, + { "sqrtg/s", FP(0x14,0x4AA), CIX, ARG_FPZ1 }, + { "sqrtf/suc", FP(0x14,0x50A), CIX, ARG_FPZ1 }, + { "sqrts/suc", FP(0x14,0x50B), CIX, ARG_FPZ1 }, + { "sqrtg/suc", FP(0x14,0x52A), CIX, ARG_FPZ1 }, + { "sqrtt/suc", FP(0x14,0x52B), CIX, ARG_FPZ1 }, + { "sqrts/sum", FP(0x14,0x54B), CIX, ARG_FPZ1 }, + { "sqrtt/sum", FP(0x14,0x56B), CIX, ARG_FPZ1 }, + { "sqrtf/su", FP(0x14,0x58A), CIX, ARG_FPZ1 }, + { "sqrts/su", FP(0x14,0x58B), CIX, ARG_FPZ1 }, + { "sqrtg/su", FP(0x14,0x5AA), CIX, ARG_FPZ1 }, + { "sqrtt/su", FP(0x14,0x5AB), CIX, ARG_FPZ1 }, + { "sqrts/sud", FP(0x14,0x5CB), CIX, ARG_FPZ1 }, + { "sqrtt/sud", FP(0x14,0x5EB), CIX, ARG_FPZ1 }, + { "sqrts/suic", FP(0x14,0x70B), CIX, ARG_FPZ1 }, + { "sqrtt/suic", FP(0x14,0x72B), CIX, ARG_FPZ1 }, + { "sqrts/suim", FP(0x14,0x74B), CIX, ARG_FPZ1 }, + { "sqrtt/suim", FP(0x14,0x76B), CIX, ARG_FPZ1 }, + { "sqrts/sui", FP(0x14,0x78B), CIX, ARG_FPZ1 }, + { "sqrtt/sui", FP(0x14,0x7AB), CIX, ARG_FPZ1 }, + { "sqrts/suid", FP(0x14,0x7CB), CIX, ARG_FPZ1 }, + { "sqrtt/suid", FP(0x14,0x7EB), CIX, ARG_FPZ1 }, + + { "addf/c", FP(0x15,0x000), BASE, ARG_FP }, + { "subf/c", FP(0x15,0x001), BASE, ARG_FP }, + { "mulf/c", FP(0x15,0x002), BASE, ARG_FP }, + { "divf/c", FP(0x15,0x003), BASE, ARG_FP }, + { "cvtdg/c", FP(0x15,0x01E), BASE, ARG_FPZ1 }, + { "addg/c", FP(0x15,0x020), BASE, ARG_FP }, + { "subg/c", FP(0x15,0x021), BASE, ARG_FP }, + { "mulg/c", FP(0x15,0x022), BASE, ARG_FP }, + { "divg/c", FP(0x15,0x023), BASE, ARG_FP }, + { "cvtgf/c", FP(0x15,0x02C), BASE, ARG_FPZ1 }, + { "cvtgd/c", FP(0x15,0x02D), BASE, ARG_FPZ1 }, + { "cvtgq/c", FP(0x15,0x02F), BASE, ARG_FPZ1 }, + { "cvtqf/c", FP(0x15,0x03C), BASE, ARG_FPZ1 }, + { "cvtqg/c", FP(0x15,0x03E), BASE, ARG_FPZ1 }, + { "addf", FP(0x15,0x080), BASE, ARG_FP }, + { "negf", FP(0x15,0x081), BASE, ARG_FPZ1 }, /* pseudo */ + { "subf", FP(0x15,0x081), BASE, ARG_FP }, + { "mulf", FP(0x15,0x082), BASE, ARG_FP }, + { "divf", FP(0x15,0x083), BASE, ARG_FP }, + { "cvtdg", FP(0x15,0x09E), BASE, ARG_FPZ1 }, + { "addg", FP(0x15,0x0A0), BASE, ARG_FP }, + { "negg", FP(0x15,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subg", FP(0x15,0x0A1), BASE, ARG_FP }, + { "mulg", FP(0x15,0x0A2), BASE, ARG_FP }, + { "divg", FP(0x15,0x0A3), BASE, ARG_FP }, + { "cmpgeq", FP(0x15,0x0A5), BASE, ARG_FP }, + { "cmpglt", FP(0x15,0x0A6), BASE, ARG_FP }, + { "cmpgle", FP(0x15,0x0A7), BASE, ARG_FP }, + { "cvtgf", FP(0x15,0x0AC), BASE, ARG_FPZ1 }, + { "cvtgd", FP(0x15,0x0AD), BASE, ARG_FPZ1 }, + { "cvtgq", FP(0x15,0x0AF), BASE, ARG_FPZ1 }, + { "cvtqf", FP(0x15,0x0BC), BASE, ARG_FPZ1 }, + { "cvtqg", FP(0x15,0x0BE), BASE, ARG_FPZ1 }, + { "addf/uc", FP(0x15,0x100), BASE, ARG_FP }, + { "subf/uc", FP(0x15,0x101), BASE, ARG_FP }, + { "mulf/uc", FP(0x15,0x102), BASE, ARG_FP }, + { "divf/uc", FP(0x15,0x103), BASE, ARG_FP }, + { "cvtdg/uc", FP(0x15,0x11E), BASE, ARG_FPZ1 }, + { "addg/uc", FP(0x15,0x120), BASE, ARG_FP }, + { "subg/uc", FP(0x15,0x121), BASE, ARG_FP }, + { "mulg/uc", FP(0x15,0x122), BASE, ARG_FP }, + { "divg/uc", FP(0x15,0x123), BASE, ARG_FP }, + { "cvtgf/uc", FP(0x15,0x12C), BASE, ARG_FPZ1 }, + { "cvtgd/uc", FP(0x15,0x12D), BASE, ARG_FPZ1 }, + { "cvtgq/vc", FP(0x15,0x12F), BASE, ARG_FPZ1 }, + { "addf/u", FP(0x15,0x180), BASE, ARG_FP }, + { "subf/u", FP(0x15,0x181), BASE, ARG_FP }, + { "mulf/u", FP(0x15,0x182), BASE, ARG_FP }, + { "divf/u", FP(0x15,0x183), BASE, ARG_FP }, + { "cvtdg/u", FP(0x15,0x19E), BASE, ARG_FPZ1 }, + { "addg/u", FP(0x15,0x1A0), BASE, ARG_FP }, + { "subg/u", FP(0x15,0x1A1), BASE, ARG_FP }, + { "mulg/u", FP(0x15,0x1A2), BASE, ARG_FP }, + { "divg/u", FP(0x15,0x1A3), BASE, ARG_FP }, + { "cvtgf/u", FP(0x15,0x1AC), BASE, ARG_FPZ1 }, + { "cvtgd/u", FP(0x15,0x1AD), BASE, ARG_FPZ1 }, + { "cvtgq/v", FP(0x15,0x1AF), BASE, ARG_FPZ1 }, + { "addf/sc", FP(0x15,0x400), BASE, ARG_FP }, + { "subf/sc", FP(0x15,0x401), BASE, ARG_FP }, + { "mulf/sc", FP(0x15,0x402), BASE, ARG_FP }, + { "divf/sc", FP(0x15,0x403), BASE, ARG_FP }, + { "cvtdg/sc", FP(0x15,0x41E), BASE, ARG_FPZ1 }, + { "addg/sc", FP(0x15,0x420), BASE, ARG_FP }, + { "subg/sc", FP(0x15,0x421), BASE, ARG_FP }, + { "mulg/sc", FP(0x15,0x422), BASE, ARG_FP }, + { "divg/sc", FP(0x15,0x423), BASE, ARG_FP }, + { "cvtgf/sc", FP(0x15,0x42C), BASE, ARG_FPZ1 }, + { "cvtgd/sc", FP(0x15,0x42D), BASE, ARG_FPZ1 }, + { "cvtgq/sc", FP(0x15,0x42F), BASE, ARG_FPZ1 }, + { "addf/s", FP(0x15,0x480), BASE, ARG_FP }, + { "negf/s", FP(0x15,0x481), BASE, ARG_FPZ1 }, /* pseudo */ + { "subf/s", FP(0x15,0x481), BASE, ARG_FP }, + { "mulf/s", FP(0x15,0x482), BASE, ARG_FP }, + { "divf/s", FP(0x15,0x483), BASE, ARG_FP }, + { "cvtdg/s", FP(0x15,0x49E), BASE, ARG_FPZ1 }, + { "addg/s", FP(0x15,0x4A0), BASE, ARG_FP }, + { "negg/s", FP(0x15,0x4A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subg/s", FP(0x15,0x4A1), BASE, ARG_FP }, + { "mulg/s", FP(0x15,0x4A2), BASE, ARG_FP }, + { "divg/s", FP(0x15,0x4A3), BASE, ARG_FP }, + { "cmpgeq/s", FP(0x15,0x4A5), BASE, ARG_FP }, + { "cmpglt/s", FP(0x15,0x4A6), BASE, ARG_FP }, + { "cmpgle/s", FP(0x15,0x4A7), BASE, ARG_FP }, + { "cvtgf/s", FP(0x15,0x4AC), BASE, ARG_FPZ1 }, + { "cvtgd/s", FP(0x15,0x4AD), BASE, ARG_FPZ1 }, + { "cvtgq/s", FP(0x15,0x4AF), BASE, ARG_FPZ1 }, + { "addf/suc", FP(0x15,0x500), BASE, ARG_FP }, + { "subf/suc", FP(0x15,0x501), BASE, ARG_FP }, + { "mulf/suc", FP(0x15,0x502), BASE, ARG_FP }, + { "divf/suc", FP(0x15,0x503), BASE, ARG_FP }, + { "cvtdg/suc", FP(0x15,0x51E), BASE, ARG_FPZ1 }, + { "addg/suc", FP(0x15,0x520), BASE, ARG_FP }, + { "subg/suc", FP(0x15,0x521), BASE, ARG_FP }, + { "mulg/suc", FP(0x15,0x522), BASE, ARG_FP }, + { "divg/suc", FP(0x15,0x523), BASE, ARG_FP }, + { "cvtgf/suc", FP(0x15,0x52C), BASE, ARG_FPZ1 }, + { "cvtgd/suc", FP(0x15,0x52D), BASE, ARG_FPZ1 }, + { "cvtgq/svc", FP(0x15,0x52F), BASE, ARG_FPZ1 }, + { "addf/su", FP(0x15,0x580), BASE, ARG_FP }, + { "subf/su", FP(0x15,0x581), BASE, ARG_FP }, + { "mulf/su", FP(0x15,0x582), BASE, ARG_FP }, + { "divf/su", FP(0x15,0x583), BASE, ARG_FP }, + { "cvtdg/su", FP(0x15,0x59E), BASE, ARG_FPZ1 }, + { "addg/su", FP(0x15,0x5A0), BASE, ARG_FP }, + { "subg/su", FP(0x15,0x5A1), BASE, ARG_FP }, + { "mulg/su", FP(0x15,0x5A2), BASE, ARG_FP }, + { "divg/su", FP(0x15,0x5A3), BASE, ARG_FP }, + { "cvtgf/su", FP(0x15,0x5AC), BASE, ARG_FPZ1 }, + { "cvtgd/su", FP(0x15,0x5AD), BASE, ARG_FPZ1 }, + { "cvtgq/sv", FP(0x15,0x5AF), BASE, ARG_FPZ1 }, + + { "adds/c", FP(0x16,0x000), BASE, ARG_FP }, + { "subs/c", FP(0x16,0x001), BASE, ARG_FP }, + { "muls/c", FP(0x16,0x002), BASE, ARG_FP }, + { "divs/c", FP(0x16,0x003), BASE, ARG_FP }, + { "addt/c", FP(0x16,0x020), BASE, ARG_FP }, + { "subt/c", FP(0x16,0x021), BASE, ARG_FP }, + { "mult/c", FP(0x16,0x022), BASE, ARG_FP }, + { "divt/c", FP(0x16,0x023), BASE, ARG_FP }, + { "cvtts/c", FP(0x16,0x02C), BASE, ARG_FPZ1 }, + { "cvttq/c", FP(0x16,0x02F), BASE, ARG_FPZ1 }, + { "cvtqs/c", FP(0x16,0x03C), BASE, ARG_FPZ1 }, + { "cvtqt/c", FP(0x16,0x03E), BASE, ARG_FPZ1 }, + { "adds/m", FP(0x16,0x040), BASE, ARG_FP }, + { "subs/m", FP(0x16,0x041), BASE, ARG_FP }, + { "muls/m", FP(0x16,0x042), BASE, ARG_FP }, + { "divs/m", FP(0x16,0x043), BASE, ARG_FP }, + { "addt/m", FP(0x16,0x060), BASE, ARG_FP }, + { "subt/m", FP(0x16,0x061), BASE, ARG_FP }, + { "mult/m", FP(0x16,0x062), BASE, ARG_FP }, + { "divt/m", FP(0x16,0x063), BASE, ARG_FP }, + { "cvtts/m", FP(0x16,0x06C), BASE, ARG_FPZ1 }, + { "cvttq/m", FP(0x16,0x06F), BASE, ARG_FPZ1 }, + { "cvtqs/m", FP(0x16,0x07C), BASE, ARG_FPZ1 }, + { "cvtqt/m", FP(0x16,0x07E), BASE, ARG_FPZ1 }, + { "adds", FP(0x16,0x080), BASE, ARG_FP }, + { "negs", FP(0x16,0x081), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs", FP(0x16,0x081), BASE, ARG_FP }, + { "muls", FP(0x16,0x082), BASE, ARG_FP }, + { "divs", FP(0x16,0x083), BASE, ARG_FP }, + { "addt", FP(0x16,0x0A0), BASE, ARG_FP }, + { "negt", FP(0x16,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt", FP(0x16,0x0A1), BASE, ARG_FP }, + { "mult", FP(0x16,0x0A2), BASE, ARG_FP }, + { "divt", FP(0x16,0x0A3), BASE, ARG_FP }, + { "cmptun", FP(0x16,0x0A4), BASE, ARG_FP }, + { "cmpteq", FP(0x16,0x0A5), BASE, ARG_FP }, + { "cmptlt", FP(0x16,0x0A6), BASE, ARG_FP }, + { "cmptle", FP(0x16,0x0A7), BASE, ARG_FP }, + { "cvtts", FP(0x16,0x0AC), BASE, ARG_FPZ1 }, + { "cvttq", FP(0x16,0x0AF), BASE, ARG_FPZ1 }, + { "cvtqs", FP(0x16,0x0BC), BASE, ARG_FPZ1 }, + { "cvtqt", FP(0x16,0x0BE), BASE, ARG_FPZ1 }, + { "adds/d", FP(0x16,0x0C0), BASE, ARG_FP }, + { "subs/d", FP(0x16,0x0C1), BASE, ARG_FP }, + { "muls/d", FP(0x16,0x0C2), BASE, ARG_FP }, + { "divs/d", FP(0x16,0x0C3), BASE, ARG_FP }, + { "addt/d", FP(0x16,0x0E0), BASE, ARG_FP }, + { "subt/d", FP(0x16,0x0E1), BASE, ARG_FP }, + { "mult/d", FP(0x16,0x0E2), BASE, ARG_FP }, + { "divt/d", FP(0x16,0x0E3), BASE, ARG_FP }, + { "cvtts/d", FP(0x16,0x0EC), BASE, ARG_FPZ1 }, + { "cvttq/d", FP(0x16,0x0EF), BASE, ARG_FPZ1 }, + { "cvtqs/d", FP(0x16,0x0FC), BASE, ARG_FPZ1 }, + { "cvtqt/d", FP(0x16,0x0FE), BASE, ARG_FPZ1 }, + { "adds/uc", FP(0x16,0x100), BASE, ARG_FP }, + { "subs/uc", FP(0x16,0x101), BASE, ARG_FP }, + { "muls/uc", FP(0x16,0x102), BASE, ARG_FP }, + { "divs/uc", FP(0x16,0x103), BASE, ARG_FP }, + { "addt/uc", FP(0x16,0x120), BASE, ARG_FP }, + { "subt/uc", FP(0x16,0x121), BASE, ARG_FP }, + { "mult/uc", FP(0x16,0x122), BASE, ARG_FP }, + { "divt/uc", FP(0x16,0x123), BASE, ARG_FP }, + { "cvtts/uc", FP(0x16,0x12C), BASE, ARG_FPZ1 }, + { "cvttq/vc", FP(0x16,0x12F), BASE, ARG_FPZ1 }, + { "adds/um", FP(0x16,0x140), BASE, ARG_FP }, + { "subs/um", FP(0x16,0x141), BASE, ARG_FP }, + { "muls/um", FP(0x16,0x142), BASE, ARG_FP }, + { "divs/um", FP(0x16,0x143), BASE, ARG_FP }, + { "addt/um", FP(0x16,0x160), BASE, ARG_FP }, + { "subt/um", FP(0x16,0x161), BASE, ARG_FP }, + { "mult/um", FP(0x16,0x162), BASE, ARG_FP }, + { "divt/um", FP(0x16,0x163), BASE, ARG_FP }, + { "cvtts/um", FP(0x16,0x16C), BASE, ARG_FPZ1 }, + { "cvttq/vm", FP(0x16,0x16F), BASE, ARG_FPZ1 }, + { "adds/u", FP(0x16,0x180), BASE, ARG_FP }, + { "subs/u", FP(0x16,0x181), BASE, ARG_FP }, + { "muls/u", FP(0x16,0x182), BASE, ARG_FP }, + { "divs/u", FP(0x16,0x183), BASE, ARG_FP }, + { "addt/u", FP(0x16,0x1A0), BASE, ARG_FP }, + { "subt/u", FP(0x16,0x1A1), BASE, ARG_FP }, + { "mult/u", FP(0x16,0x1A2), BASE, ARG_FP }, + { "divt/u", FP(0x16,0x1A3), BASE, ARG_FP }, + { "cvtts/u", FP(0x16,0x1AC), BASE, ARG_FPZ1 }, + { "cvttq/v", FP(0x16,0x1AF), BASE, ARG_FPZ1 }, + { "adds/ud", FP(0x16,0x1C0), BASE, ARG_FP }, + { "subs/ud", FP(0x16,0x1C1), BASE, ARG_FP }, + { "muls/ud", FP(0x16,0x1C2), BASE, ARG_FP }, + { "divs/ud", FP(0x16,0x1C3), BASE, ARG_FP }, + { "addt/ud", FP(0x16,0x1E0), BASE, ARG_FP }, + { "subt/ud", FP(0x16,0x1E1), BASE, ARG_FP }, + { "mult/ud", FP(0x16,0x1E2), BASE, ARG_FP }, + { "divt/ud", FP(0x16,0x1E3), BASE, ARG_FP }, + { "cvtts/ud", FP(0x16,0x1EC), BASE, ARG_FPZ1 }, + { "cvttq/vd", FP(0x16,0x1EF), BASE, ARG_FPZ1 }, + { "cvtst", FP(0x16,0x2AC), BASE, ARG_FPZ1 }, + { "adds/suc", FP(0x16,0x500), BASE, ARG_FP }, + { "subs/suc", FP(0x16,0x501), BASE, ARG_FP }, + { "muls/suc", FP(0x16,0x502), BASE, ARG_FP }, + { "divs/suc", FP(0x16,0x503), BASE, ARG_FP }, + { "addt/suc", FP(0x16,0x520), BASE, ARG_FP }, + { "subt/suc", FP(0x16,0x521), BASE, ARG_FP }, + { "mult/suc", FP(0x16,0x522), BASE, ARG_FP }, + { "divt/suc", FP(0x16,0x523), BASE, ARG_FP }, + { "cvtts/suc", FP(0x16,0x52C), BASE, ARG_FPZ1 }, + { "cvttq/svc", FP(0x16,0x52F), BASE, ARG_FPZ1 }, + { "adds/sum", FP(0x16,0x540), BASE, ARG_FP }, + { "subs/sum", FP(0x16,0x541), BASE, ARG_FP }, + { "muls/sum", FP(0x16,0x542), BASE, ARG_FP }, + { "divs/sum", FP(0x16,0x543), BASE, ARG_FP }, + { "addt/sum", FP(0x16,0x560), BASE, ARG_FP }, + { "subt/sum", FP(0x16,0x561), BASE, ARG_FP }, + { "mult/sum", FP(0x16,0x562), BASE, ARG_FP }, + { "divt/sum", FP(0x16,0x563), BASE, ARG_FP }, + { "cvtts/sum", FP(0x16,0x56C), BASE, ARG_FPZ1 }, + { "cvttq/svm", FP(0x16,0x56F), BASE, ARG_FPZ1 }, + { "adds/su", FP(0x16,0x580), BASE, ARG_FP }, + { "negs/su", FP(0x16,0x581), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs/su", FP(0x16,0x581), BASE, ARG_FP }, + { "muls/su", FP(0x16,0x582), BASE, ARG_FP }, + { "divs/su", FP(0x16,0x583), BASE, ARG_FP }, + { "addt/su", FP(0x16,0x5A0), BASE, ARG_FP }, + { "negt/su", FP(0x16,0x5A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt/su", FP(0x16,0x5A1), BASE, ARG_FP }, + { "mult/su", FP(0x16,0x5A2), BASE, ARG_FP }, + { "divt/su", FP(0x16,0x5A3), BASE, ARG_FP }, + { "cmptun/su", FP(0x16,0x5A4), BASE, ARG_FP }, + { "cmpteq/su", FP(0x16,0x5A5), BASE, ARG_FP }, + { "cmptlt/su", FP(0x16,0x5A6), BASE, ARG_FP }, + { "cmptle/su", FP(0x16,0x5A7), BASE, ARG_FP }, + { "cvtts/su", FP(0x16,0x5AC), BASE, ARG_FPZ1 }, + { "cvttq/sv", FP(0x16,0x5AF), BASE, ARG_FPZ1 }, + { "adds/sud", FP(0x16,0x5C0), BASE, ARG_FP }, + { "subs/sud", FP(0x16,0x5C1), BASE, ARG_FP }, + { "muls/sud", FP(0x16,0x5C2), BASE, ARG_FP }, + { "divs/sud", FP(0x16,0x5C3), BASE, ARG_FP }, + { "addt/sud", FP(0x16,0x5E0), BASE, ARG_FP }, + { "subt/sud", FP(0x16,0x5E1), BASE, ARG_FP }, + { "mult/sud", FP(0x16,0x5E2), BASE, ARG_FP }, + { "divt/sud", FP(0x16,0x5E3), BASE, ARG_FP }, + { "cvtts/sud", FP(0x16,0x5EC), BASE, ARG_FPZ1 }, + { "cvttq/svd", FP(0x16,0x5EF), BASE, ARG_FPZ1 }, + { "cvtst/s", FP(0x16,0x6AC), BASE, ARG_FPZ1 }, + { "adds/suic", FP(0x16,0x700), BASE, ARG_FP }, + { "subs/suic", FP(0x16,0x701), BASE, ARG_FP }, + { "muls/suic", FP(0x16,0x702), BASE, ARG_FP }, + { "divs/suic", FP(0x16,0x703), BASE, ARG_FP }, + { "addt/suic", FP(0x16,0x720), BASE, ARG_FP }, + { "subt/suic", FP(0x16,0x721), BASE, ARG_FP }, + { "mult/suic", FP(0x16,0x722), BASE, ARG_FP }, + { "divt/suic", FP(0x16,0x723), BASE, ARG_FP }, + { "cvtts/suic", FP(0x16,0x72C), BASE, ARG_FPZ1 }, + { "cvttq/svic", FP(0x16,0x72F), BASE, ARG_FPZ1 }, + { "cvtqs/suic", FP(0x16,0x73C), BASE, ARG_FPZ1 }, + { "cvtqt/suic", FP(0x16,0x73E), BASE, ARG_FPZ1 }, + { "adds/suim", FP(0x16,0x740), BASE, ARG_FP }, + { "subs/suim", FP(0x16,0x741), BASE, ARG_FP }, + { "muls/suim", FP(0x16,0x742), BASE, ARG_FP }, + { "divs/suim", FP(0x16,0x743), BASE, ARG_FP }, + { "addt/suim", FP(0x16,0x760), BASE, ARG_FP }, + { "subt/suim", FP(0x16,0x761), BASE, ARG_FP }, + { "mult/suim", FP(0x16,0x762), BASE, ARG_FP }, + { "divt/suim", FP(0x16,0x763), BASE, ARG_FP }, + { "cvtts/suim", FP(0x16,0x76C), BASE, ARG_FPZ1 }, + { "cvttq/svim", FP(0x16,0x76F), BASE, ARG_FPZ1 }, + { "cvtqs/suim", FP(0x16,0x77C), BASE, ARG_FPZ1 }, + { "cvtqt/suim", FP(0x16,0x77E), BASE, ARG_FPZ1 }, + { "adds/sui", FP(0x16,0x780), BASE, ARG_FP }, + { "negs/sui", FP(0x16,0x781), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs/sui", FP(0x16,0x781), BASE, ARG_FP }, + { "muls/sui", FP(0x16,0x782), BASE, ARG_FP }, + { "divs/sui", FP(0x16,0x783), BASE, ARG_FP }, + { "addt/sui", FP(0x16,0x7A0), BASE, ARG_FP }, + { "negt/sui", FP(0x16,0x7A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt/sui", FP(0x16,0x7A1), BASE, ARG_FP }, + { "mult/sui", FP(0x16,0x7A2), BASE, ARG_FP }, + { "divt/sui", FP(0x16,0x7A3), BASE, ARG_FP }, + { "cvtts/sui", FP(0x16,0x7AC), BASE, ARG_FPZ1 }, + { "cvttq/svi", FP(0x16,0x7AF), BASE, ARG_FPZ1 }, + { "cvtqs/sui", FP(0x16,0x7BC), BASE, ARG_FPZ1 }, + { "cvtqt/sui", FP(0x16,0x7BE), BASE, ARG_FPZ1 }, + { "adds/suid", FP(0x16,0x7C0), BASE, ARG_FP }, + { "subs/suid", FP(0x16,0x7C1), BASE, ARG_FP }, + { "muls/suid", FP(0x16,0x7C2), BASE, ARG_FP }, + { "divs/suid", FP(0x16,0x7C3), BASE, ARG_FP }, + { "addt/suid", FP(0x16,0x7E0), BASE, ARG_FP }, + { "subt/suid", FP(0x16,0x7E1), BASE, ARG_FP }, + { "mult/suid", FP(0x16,0x7E2), BASE, ARG_FP }, + { "divt/suid", FP(0x16,0x7E3), BASE, ARG_FP }, + { "cvtts/suid", FP(0x16,0x7EC), BASE, ARG_FPZ1 }, + { "cvttq/svid", FP(0x16,0x7EF), BASE, ARG_FPZ1 }, + { "cvtqs/suid", FP(0x16,0x7FC), BASE, ARG_FPZ1 }, + { "cvtqt/suid", FP(0x16,0x7FE), BASE, ARG_FPZ1 }, + + { "cvtlq", FP(0x17,0x010), BASE, ARG_FPZ1 }, + { "fnop", FP(0x17,0x020), BASE, { ZA, ZB, ZC } }, /* pseudo */ + { "fclr", FP(0x17,0x020), BASE, { ZA, ZB, FC } }, /* pseudo */ + { "fabs", FP(0x17,0x020), BASE, ARG_FPZ1 }, /* pseudo */ + { "fmov", FP(0x17,0x020), BASE, { FA, RBA, FC } }, /* pseudo */ + { "cpys", FP(0x17,0x020), BASE, ARG_FP }, + { "fneg", FP(0x17,0x021), BASE, { FA, RBA, FC } }, /* pseudo */ + { "cpysn", FP(0x17,0x021), BASE, ARG_FP }, + { "cpyse", FP(0x17,0x022), BASE, ARG_FP }, + { "mt_fpcr", FP(0x17,0x024), BASE, { FA, RBA, RCA } }, + { "mf_fpcr", FP(0x17,0x025), BASE, { FA, RBA, RCA } }, + { "fcmoveq", FP(0x17,0x02A), BASE, ARG_FP }, + { "fcmovne", FP(0x17,0x02B), BASE, ARG_FP }, + { "fcmovlt", FP(0x17,0x02C), BASE, ARG_FP }, + { "fcmovge", FP(0x17,0x02D), BASE, ARG_FP }, + { "fcmovle", FP(0x17,0x02E), BASE, ARG_FP }, + { "fcmovgt", FP(0x17,0x02F), BASE, ARG_FP }, + { "cvtql", FP(0x17,0x030), BASE, ARG_FPZ1 }, + { "cvtql/v", FP(0x17,0x130), BASE, ARG_FPZ1 }, + { "cvtql/sv", FP(0x17,0x530), BASE, ARG_FPZ1 }, + + { "trapb", MFC(0x18,0x0000), BASE, ARG_NONE }, + { "draint", MFC(0x18,0x0000), BASE, ARG_NONE }, /* alias */ + { "excb", MFC(0x18,0x0400), BASE, ARG_NONE }, + { "mb", MFC(0x18,0x4000), BASE, ARG_NONE }, + { "wmb", MFC(0x18,0x4400), BASE, ARG_NONE }, + { "fetch", MFC(0x18,0x8000), BASE, { ZA, PRB } }, + { "fetch_m", MFC(0x18,0xA000), BASE, { ZA, PRB } }, + { "rpcc", MFC(0x18,0xC000), BASE, { RA } }, + { "rc", MFC(0x18,0xE000), BASE, { RA } }, + { "ecb", MFC(0x18,0xE800), BASE, { ZA, PRB } }, /* ev56 una */ + { "rs", MFC(0x18,0xF000), BASE, { RA } }, + { "wh64", MFC(0x18,0xF800), BASE, { ZA, PRB } }, /* ev56 una */ + { "wh64en", MFC(0x18,0xFC00), BASE, { ZA, PRB } }, /* ev7 una */ + + { "hw_mfpr", OPR(0x19,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } }, + { "hw_mfpr", OP(0x19), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } }, + { "hw_mfpr", OP(0x19), OP_MASK, EV6, { RA, ZB, EV6HWINDEX } }, + { "hw_mfpr/i", OPR(0x19,0x01), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/a", OPR(0x19,0x02), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/ai", OPR(0x19,0x03), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/p", OPR(0x19,0x04), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pi", OPR(0x19,0x05), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pa", OPR(0x19,0x06), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pai", OPR(0x19,0x07), EV4, ARG_EV4HWMPR }, + { "pal19", PCD(0x19), BASE, ARG_PCD }, + + { "jmp", MBR_(0x1A,0), MBR_MASK | 0x3FFF, /* pseudo */ + BASE, { ZA, CPRB } }, + { "jmp", MBR(0x1A,0), BASE, { RA, CPRB, JMPHINT } }, + { "jsr", MBR(0x1A,1), BASE, { RA, CPRB, JMPHINT } }, + { "ret", MBR_(0x1A,2) | (31 << 21) | (26 << 16) | 1,/* pseudo */ + 0xFFFFFFFF, BASE, { 0 } }, + { "ret", MBR(0x1A,2), BASE, { RA, CPRB, RETHINT } }, + { "jcr", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, /* alias */ + { "jsr_coroutine", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, + + { "hw_ldl", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM }, + { "hw_ldl", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM }, + { "hw_ldl", EV6HWMEM(0x1B,0x8), EV6, ARG_EV6HWMEM }, + { "hw_ldl/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM }, + { "hw_ldl/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM }, + { "hw_ldl/a", EV6HWMEM(0x1B,0xC), EV6, ARG_EV6HWMEM }, + { "hw_ldl/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ldl/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM }, + { "hw_ldl/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM }, + { "hw_ldl/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ldl/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ldl/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM }, + { "hw_ldl/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM }, + { "hw_ldl/p", EV6HWMEM(0x1B,0x0), EV6, ARG_EV6HWMEM }, + { "hw_ldl/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ldl/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ldl/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM }, + { "hw_ldl/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM }, + { "hw_ldl/v", EV6HWMEM(0x1B,0x4), EV6, ARG_EV6HWMEM }, + { "hw_ldl/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ldl/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM }, + { "hw_ldl/w", EV6HWMEM(0x1B,0xA), EV6, ARG_EV6HWMEM }, + { "hw_ldl/wa", EV6HWMEM(0x1B,0xE), EV6, ARG_EV6HWMEM }, + { "hw_ldl/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ldl/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/a", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/av", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/aw", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/awv", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/p", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/p", EV6HWMEM(0x1B,0x2), EV6, ARG_EV6HWMEM }, + { "hw_ldl_l/pa", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pav", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/paw", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pawv", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pv", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pw", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pwv", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/v", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/w", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/wv", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "hw_ldq", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM }, + { "hw_ldq", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM }, + { "hw_ldq", EV6HWMEM(0x1B,0x9), EV6, ARG_EV6HWMEM }, + { "hw_ldq/a", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM }, + { "hw_ldq/a", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM }, + { "hw_ldq/a", EV6HWMEM(0x1B,0xD), EV6, ARG_EV6HWMEM }, + { "hw_ldq/al", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ldq/ar", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM }, + { "hw_ldq/av", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM }, + { "hw_ldq/avl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ldq/aw", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awl", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ldq/p", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM }, + { "hw_ldq/p", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM }, + { "hw_ldq/p", EV6HWMEM(0x1B,0x1), EV6, ARG_EV6HWMEM }, + { "hw_ldq/pa", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pa", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pal", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ldq/par", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pav", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pavl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ldq/paw", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawl", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pl", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pr", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pw", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwl", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/r", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM }, + { "hw_ldq/v", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM }, + { "hw_ldq/v", EV6HWMEM(0x1B,0x5), EV6, ARG_EV6HWMEM }, + { "hw_ldq/vl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ldq/w", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/w", EV6HWMEM(0x1B,0xB), EV6, ARG_EV6HWMEM }, + { "hw_ldq/wa", EV6HWMEM(0x1B,0xF), EV6, ARG_EV6HWMEM }, + { "hw_ldq/wl", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/wv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/wvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/a", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/av", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/aw", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/awv", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/p", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/p", EV6HWMEM(0x1B,0x3), EV6, ARG_EV6HWMEM }, + { "hw_ldq_l/pa", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pav", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/paw", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pawv", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pv", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pw", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pwv", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/v", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/w", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/wv", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ld", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM }, + { "hw_ld", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM }, + { "hw_ld/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM }, + { "hw_ld/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM }, + { "hw_ld/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ld/aq", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM }, + { "hw_ld/aq", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM }, + { "hw_ld/aql", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ld/aqv", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM }, + { "hw_ld/aqvl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ld/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM }, + { "hw_ld/arq", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM }, + { "hw_ld/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM }, + { "hw_ld/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ld/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM }, + { "hw_ld/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ld/awq", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM }, + { "hw_ld/awql", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ld/awqv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM }, + { "hw_ld/awqvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ld/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM }, + { "hw_ld/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ld/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ld/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM }, + { "hw_ld/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM }, + { "hw_ld/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM }, + { "hw_ld/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM }, + { "hw_ld/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ld/paq", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM }, + { "hw_ld/paq", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM }, + { "hw_ld/paql", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ld/paqv", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM }, + { "hw_ld/paqvl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ld/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM }, + { "hw_ld/parq", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM }, + { "hw_ld/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM }, + { "hw_ld/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ld/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawq", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawql", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawqv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawqvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ld/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ld/pq", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM }, + { "hw_ld/pq", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM }, + { "hw_ld/pql", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ld/pqv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM }, + { "hw_ld/pqvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ld/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM }, + { "hw_ld/prq", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM }, + { "hw_ld/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM }, + { "hw_ld/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ld/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwq", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwql", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwqv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwqvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ld/q", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM }, + { "hw_ld/q", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM }, + { "hw_ld/ql", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ld/qv", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM }, + { "hw_ld/qvl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ld/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM }, + { "hw_ld/rq", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM }, + { "hw_ld/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM }, + { "hw_ld/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ld/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM }, + { "hw_ld/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ld/wq", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM }, + { "hw_ld/wql", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ld/wqv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM }, + { "hw_ld/wqvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ld/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM }, + { "hw_ld/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "pal1b", PCD(0x1B), BASE, ARG_PCD }, + + { "sextb", OPR(0x1C, 0x00), BWX, ARG_OPRZ1 }, + { "sextw", OPR(0x1C, 0x01), BWX, ARG_OPRZ1 }, + { "ctpop", OPR(0x1C, 0x30), CIX, ARG_OPRZ1 }, + { "perr", OPR(0x1C, 0x31), MAX, ARG_OPR }, + { "ctlz", OPR(0x1C, 0x32), CIX, ARG_OPRZ1 }, + { "cttz", OPR(0x1C, 0x33), CIX, ARG_OPRZ1 }, + { "unpkbw", OPR(0x1C, 0x34), MAX, ARG_OPRZ1 }, + { "unpkbl", OPR(0x1C, 0x35), MAX, ARG_OPRZ1 }, + { "pkwb", OPR(0x1C, 0x36), MAX, ARG_OPRZ1 }, + { "pklb", OPR(0x1C, 0x37), MAX, ARG_OPRZ1 }, + { "minsb8", OPR(0x1C, 0x38), MAX, ARG_OPR }, + { "minsb8", OPRL(0x1C, 0x38), MAX, ARG_OPRL }, + { "minsw4", OPR(0x1C, 0x39), MAX, ARG_OPR }, + { "minsw4", OPRL(0x1C, 0x39), MAX, ARG_OPRL }, + { "minub8", OPR(0x1C, 0x3A), MAX, ARG_OPR }, + { "minub8", OPRL(0x1C, 0x3A), MAX, ARG_OPRL }, + { "minuw4", OPR(0x1C, 0x3B), MAX, ARG_OPR }, + { "minuw4", OPRL(0x1C, 0x3B), MAX, ARG_OPRL }, + { "maxub8", OPR(0x1C, 0x3C), MAX, ARG_OPR }, + { "maxub8", OPRL(0x1C, 0x3C), MAX, ARG_OPRL }, + { "maxuw4", OPR(0x1C, 0x3D), MAX, ARG_OPR }, + { "maxuw4", OPRL(0x1C, 0x3D), MAX, ARG_OPRL }, + { "maxsb8", OPR(0x1C, 0x3E), MAX, ARG_OPR }, + { "maxsb8", OPRL(0x1C, 0x3E), MAX, ARG_OPRL }, + { "maxsw4", OPR(0x1C, 0x3F), MAX, ARG_OPR }, + { "maxsw4", OPRL(0x1C, 0x3F), MAX, ARG_OPRL }, + { "ftoit", FP(0x1C, 0x70), CIX, { FA, ZB, RC } }, + { "ftois", FP(0x1C, 0x78), CIX, { FA, ZB, RC } }, + + { "hw_mtpr", OPR(0x1D,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } }, + { "hw_mtpr", OP(0x1D), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } }, + { "hw_mtpr", OP(0x1D), OP_MASK, EV6, { ZA, RB, EV6HWINDEX } }, + { "hw_mtpr/i", OPR(0x1D,0x01), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/a", OPR(0x1D,0x02), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/ai", OPR(0x1D,0x03), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/p", OPR(0x1D,0x04), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pi", OPR(0x1D,0x05), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pa", OPR(0x1D,0x06), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pai", OPR(0x1D,0x07), EV4, ARG_EV4HWMPR }, + { "pal1d", PCD(0x1D), BASE, ARG_PCD }, + + { "hw_rei", SPCD(0x1E,0x3FF8000), EV4|EV5, ARG_NONE }, + { "hw_rei_stall", SPCD(0x1E,0x3FFC000), EV5, ARG_NONE }, + { "hw_jmp", EV6HWMBR(0x1E,0x0), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_jsr", EV6HWMBR(0x1E,0x2), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_ret", EV6HWMBR(0x1E,0x4), EV6, { ZA, PRB } }, + { "hw_jcr", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, + { "hw_coroutine", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, /* alias */ + { "hw_jmp/stall", EV6HWMBR(0x1E,0x1), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_jsr/stall", EV6HWMBR(0x1E,0x3), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_ret/stall", EV6HWMBR(0x1E,0x5), EV6, { ZA, PRB } }, + { "hw_jcr/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, + { "hw_coroutine/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, /* alias */ + { "pal1e", PCD(0x1E), BASE, ARG_PCD }, + + { "hw_stl", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM }, + { "hw_stl", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM }, + { "hw_stl", EV6HWMEM(0x1F,0x4), EV6, ARG_EV6HWMEM }, /* ??? 8 */ + { "hw_stl/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM }, + { "hw_stl/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM }, + { "hw_stl/a", EV6HWMEM(0x1F,0xC), EV6, ARG_EV6HWMEM }, + { "hw_stl/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_stl/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM }, + { "hw_stl/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM }, + { "hw_stl/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_stl/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_stl/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM }, + { "hw_stl/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM }, + { "hw_stl/p", EV6HWMEM(0x1F,0x0), EV6, ARG_EV6HWMEM }, + { "hw_stl/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM }, + { "hw_stl/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM }, + { "hw_stl/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_stl/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM }, + { "hw_stl/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_stl/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_stl/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM }, + { "hw_stl/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM }, + { "hw_stl/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_stl/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM }, + { "hw_stl/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM }, + { "hw_stl/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "hw_stl_c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/a", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/av", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/p", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/p", EV6HWMEM(0x1F,0x2), EV6, ARG_EV6HWMEM }, + { "hw_stl_c/pa", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/pav", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/pv", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/v", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "hw_stq", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM }, + { "hw_stq", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM }, + { "hw_stq", EV6HWMEM(0x1F,0x5), EV6, ARG_EV6HWMEM }, /* ??? 9 */ + { "hw_stq/a", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM }, + { "hw_stq/a", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM }, + { "hw_stq/a", EV6HWMEM(0x1F,0xD), EV6, ARG_EV6HWMEM }, + { "hw_stq/ac", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_stq/ar", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM }, + { "hw_stq/av", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM }, + { "hw_stq/avc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_stq/c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_stq/p", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM }, + { "hw_stq/p", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM }, + { "hw_stq/p", EV6HWMEM(0x1F,0x1), EV6, ARG_EV6HWMEM }, + { "hw_stq/pa", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM }, + { "hw_stq/pa", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM }, + { "hw_stq/pac", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_stq/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM }, + { "hw_stq/par", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM }, + { "hw_stq/pav", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM }, + { "hw_stq/pavc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_stq/pc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_stq/pr", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM }, + { "hw_stq/pv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM }, + { "hw_stq/pvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_stq/r", EV4HWMEM(0x1F,0x3), EV4, ARG_EV4HWMEM }, + { "hw_stq/v", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM }, + { "hw_stq/vc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_stq_c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/a", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/av", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/p", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/p", EV6HWMEM(0x1F,0x3), EV6, ARG_EV6HWMEM }, + { "hw_stq_c/pa", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/pav", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/pv", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/v", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_st", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM }, + { "hw_st", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM }, + { "hw_st/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM }, + { "hw_st/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM }, + { "hw_st/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_st/aq", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM }, + { "hw_st/aq", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM }, + { "hw_st/aqc", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_st/aqv", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM }, + { "hw_st/aqvc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_st/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM }, + { "hw_st/arq", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM }, + { "hw_st/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM }, + { "hw_st/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_st/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_st/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM }, + { "hw_st/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM }, + { "hw_st/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM }, + { "hw_st/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM }, + { "hw_st/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_st/paq", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM }, + { "hw_st/paq", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM }, + { "hw_st/paqc", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_st/paqv", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM }, + { "hw_st/paqvc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_st/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM }, + { "hw_st/parq", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM }, + { "hw_st/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM }, + { "hw_st/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_st/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_st/pq", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM }, + { "hw_st/pq", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM }, + { "hw_st/pqc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_st/pqv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM }, + { "hw_st/pqvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_st/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM }, + { "hw_st/prq", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM }, + { "hw_st/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM }, + { "hw_st/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_st/q", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM }, + { "hw_st/q", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM }, + { "hw_st/qc", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_st/qv", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM }, + { "hw_st/qvc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_st/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM }, + { "hw_st/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM }, + { "hw_st/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "pal1f", PCD(0x1F), BASE, ARG_PCD }, + + { "ldf", MEM(0x20), BASE, ARG_FMEM }, + { "ldg", MEM(0x21), BASE, ARG_FMEM }, + { "lds", MEM(0x22), BASE, ARG_FMEM }, + { "ldt", MEM(0x23), BASE, ARG_FMEM }, + { "stf", MEM(0x24), BASE, ARG_FMEM }, + { "stg", MEM(0x25), BASE, ARG_FMEM }, + { "sts", MEM(0x26), BASE, ARG_FMEM }, + { "stt", MEM(0x27), BASE, ARG_FMEM }, + + { "ldl", MEM(0x28), BASE, ARG_MEM }, + { "ldq", MEM(0x29), BASE, ARG_MEM }, + { "ldl_l", MEM(0x2A), BASE, ARG_MEM }, + { "ldq_l", MEM(0x2B), BASE, ARG_MEM }, + { "stl", MEM(0x2C), BASE, ARG_MEM }, + { "stq", MEM(0x2D), BASE, ARG_MEM }, + { "stl_c", MEM(0x2E), BASE, ARG_MEM }, + { "stq_c", MEM(0x2F), BASE, ARG_MEM }, + + { "br", BRA(0x30), BASE, { ZA, BDISP } }, /* pseudo */ + { "br", BRA(0x30), BASE, ARG_BRA }, + { "fbeq", BRA(0x31), BASE, ARG_FBRA }, + { "fblt", BRA(0x32), BASE, ARG_FBRA }, + { "fble", BRA(0x33), BASE, ARG_FBRA }, + { "bsr", BRA(0x34), BASE, ARG_BRA }, + { "fbne", BRA(0x35), BASE, ARG_FBRA }, + { "fbge", BRA(0x36), BASE, ARG_FBRA }, + { "fbgt", BRA(0x37), BASE, ARG_FBRA }, + { "blbc", BRA(0x38), BASE, ARG_BRA }, + { "beq", BRA(0x39), BASE, ARG_BRA }, + { "blt", BRA(0x3A), BASE, ARG_BRA }, + { "ble", BRA(0x3B), BASE, ARG_BRA }, + { "blbs", BRA(0x3C), BASE, ARG_BRA }, + { "bne", BRA(0x3D), BASE, ARG_BRA }, + { "bge", BRA(0x3E), BASE, ARG_BRA }, + { "bgt", BRA(0x3F), BASE, ARG_BRA }, +}; + +const unsigned alpha_num_opcodes = sizeof(alpha_opcodes)/sizeof(*alpha_opcodes); + +/* OSF register names. */ + +static const char * const osf_regnames[64] = { + "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +/* VMS register names. */ + +static const char * const vms_regnames[64] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", + "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", + "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", + "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", + "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" +}; + +/* Disassemble Alpha instructions. */ + +int +print_insn_alpha (bfd_vma memaddr, struct disassemble_info *info) +{ + static const struct alpha_opcode *opcode_index[AXP_NOPS+1]; + const char * const * regnames; + const struct alpha_opcode *opcode, *opcode_end; + const unsigned char *opindex; + unsigned insn, op, isa_mask; + int need_comma; + + /* Initialize the majorop table the first time through */ + if (!opcode_index[0]) + { + opcode = alpha_opcodes; + opcode_end = opcode + alpha_num_opcodes; + + for (op = 0; op < AXP_NOPS; ++op) + { + opcode_index[op] = opcode; + while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) + ++opcode; + } + opcode_index[op] = opcode; + } + + if (info->flavour == bfd_target_evax_flavour) + regnames = vms_regnames; + else + regnames = osf_regnames; + + isa_mask = AXP_OPCODE_NOPAL; + switch (info->mach) + { + case bfd_mach_alpha_ev4: + isa_mask |= AXP_OPCODE_EV4; + break; + case bfd_mach_alpha_ev5: + isa_mask |= AXP_OPCODE_EV5; + break; + case bfd_mach_alpha_ev6: + isa_mask |= AXP_OPCODE_EV6; + break; + } + + /* Read the insn into a host word */ + { + bfd_byte buffer[4]; + int status = (*info->read_memory_func) (memaddr, buffer, 4, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + insn = bfd_getl32 (buffer); + } + + /* Get the major opcode of the instruction. */ + op = AXP_OP (insn); + + /* Find the first match in the opcode table. */ + opcode_end = opcode_index[op + 1]; + for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) + { + if ((insn ^ opcode->opcode) & opcode->mask) + continue; + + if (!(opcode->flags & isa_mask)) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + { + int invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + const struct alpha_operand *operand = alpha_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, &invalid); + } + if (invalid) + continue; + } + + /* The instruction is valid. */ + goto found; + } + + /* No instruction found */ + (*info->fprintf_func) (info->stream, ".long %#08x", insn); + + return 4; + +found: + (*info->fprintf_func) (info->stream, "%s", opcode->name); + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "\t"); + + /* Now extract and print the operands. */ + need_comma = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + const struct alpha_operand *operand = alpha_operands + *opindex; + int value; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & AXP_OPERAND_FAKE) != 0) + continue; + + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, (int *) NULL); + else + { + value = (insn >> operand->shift) & ((1 << operand->bits) - 1); + if (operand->flags & AXP_OPERAND_SIGNED) + { + int signbit = 1 << (operand->bits - 1); + value = (value ^ signbit) - signbit; + } + } + + if (need_comma && + ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA)) + != AXP_OPERAND_PARENS)) + { + (*info->fprintf_func) (info->stream, ","); + } + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, "("); + + /* Print the operand as directed by the flags. */ + if (operand->flags & AXP_OPERAND_IR) + (*info->fprintf_func) (info->stream, "%s", regnames[value]); + else if (operand->flags & AXP_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); + else if (operand->flags & AXP_OPERAND_RELATIVE) + (*info->print_address_func) (memaddr + 4 + value, info); + else if (operand->flags & AXP_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%d", value); + else + (*info->fprintf_func) (info->stream, "%#x", value); + + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, ")"); + need_comma = 1; + } + + return 4; +} diff --git a/qemu/qemu-git/.svn/text-base/alpha.ld.svn-base b/qemu/qemu-git/.svn/text-base/alpha.ld.svn-base new file mode 100644 index 0000000..906d76b --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/alpha.ld.svn-base @@ -0,0 +1,127 @@ +OUTPUT_FORMAT("elf64-alpha", "elf64-alpha", + "elf64-alpha") +OUTPUT_ARCH(alpha) +ENTRY(__start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/.svn/text-base/arm-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/arm-dis.c.svn-base new file mode 100644 index 0000000..2c67d8f --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/arm-dis.c.svn-base @@ -0,0 +1,4117 @@ +/* Instruction printing code for the ARM + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + 2007, Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) + Modification by James G. Smith (jsmith@cygnus.co.uk) + + This file is part of libopcodes. + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Start of qemu specific additions. Mostly this is stub definitions + for things we don't care about. */ + +#include "dis-asm.h" +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') + +#define ARM_EXT_V1 0 +#define ARM_EXT_V2 0 +#define ARM_EXT_V2S 0 +#define ARM_EXT_V3 0 +#define ARM_EXT_V3M 0 +#define ARM_EXT_V4 0 +#define ARM_EXT_V4T 0 +#define ARM_EXT_V5 0 +#define ARM_EXT_V5T 0 +#define ARM_EXT_V5ExP 0 +#define ARM_EXT_V5E 0 +#define ARM_EXT_V5J 0 +#define ARM_EXT_V6 0 +#define ARM_EXT_V6K 0 +#define ARM_EXT_V6Z 0 +#define ARM_EXT_V6T2 0 +#define ARM_EXT_V7 0 +#define ARM_EXT_DIV 0 + +/* Co-processor space extensions. */ +#define ARM_CEXT_XSCALE 0 +#define ARM_CEXT_MAVERICK 0 +#define ARM_CEXT_IWMMXT 0 + +#define FPU_FPA_EXT_V1 0 +#define FPU_FPA_EXT_V2 0 +#define FPU_VFP_EXT_NONE 0 +#define FPU_VFP_EXT_V1xD 0 +#define FPU_VFP_EXT_V1 0 +#define FPU_VFP_EXT_V2 0 +#define FPU_MAVERICK 0 +#define FPU_VFP_EXT_V3 0 +#define FPU_NEON_EXT_V1 0 + +int floatformat_ieee_single_little; +/* Assume host uses ieee float. */ +static void floatformat_to_double (int *ignored, unsigned char *data, + double *dest) +{ + union { + uint32_t i; + float f; + } u; + u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + *dest = u.f; +} + +/* End of qemu specific additions. */ + +/* FIXME: Belongs in global header. */ +#ifndef strneq +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) +#endif + +#ifndef NUM_ELEM +#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) +#endif + +struct opcode32 +{ + unsigned long arch; /* Architecture defining this insn. */ + unsigned long value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ +}; + +struct opcode16 +{ + unsigned long arch; /* Architecture defining this insn. */ + unsigned short value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ +}; + +/* print_insn_coprocessor recognizes the following format control codes: + + %% % + + %c print condition code (always bits 28-31 in ARM mode) + %q print shifter argument + %u print condition code (unconditional in ARM mode) + %A print address for ldc/stc/ldf/stf instruction + %B print vstm/vldm register list + %C print vstr/vldr address operand + %I print cirrus signed shift immediate: bits 0..3|4..6 + %F print the COUNT field of a LFM/SFM instruction. + %P print floating point precision in arithmetic insn + %Q print floating point precision in ldf/stf insn + %R print floating point rounding mode + + %r print as an ARM register + %d print the bitfield in decimal + %k print immediate for VFPv3 conversion instruction + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + %f print a floating point constant if >7 else a + floating point register + %w print as an iWMMXt width field - [bhwd]ss/us + %g print as an iWMMXt 64-bit register + %G print as an iWMMXt general purpose or control register + %D print as a NEON D register + %Q print as a NEON Q register + + %y print a single precision VFP reg. + Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair + %z print a double precision VFP reg + Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %L print as an iWMMXt N/M width field. + %Z print the Immediate of a WSHUFH instruction. + %l like 'A' except use byte offsets for 'B' & 'H' + versions. + %i print 5-bit immediate in bits 8,3..0 + (print "32" when 0) + %r print register offset address for wldt/wstr instruction +*/ + +/* Common coprocessor opcodes shared between Arm and Thumb-2. */ + +static const struct opcode32 coprocessor_opcodes[] = +{ + /* XScale instructions. */ + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, + + /* Intel Wireless MMX technology instructions. */ +#define FIRST_IWMMXT_INSN 0x0e130130 +#define IWMMXT_INSN_COUNT 73 + {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"}, + {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"}, + {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"}, + {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"}, + + /* Floating point coprocessor (FPA) instructions */ + {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, + {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, + {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, + {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, + + /* Register load/store */ + {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"}, + {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"}, + + /* Data transfer between ARM and NEON registers */ + {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"}, + {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"}, + {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"}, + {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"}, + + /* Floating point coprocessor (VFP) instructions */ + {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, + {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, + {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"}, + {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"}, + {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, + {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, + {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, "}, + {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"}, + {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"}, + {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"}, + {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"}, + {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"}, + {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"}, + {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"}, + + /* Cirrus coprocessor instructions. */ + {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"}, + {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"}, + {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + + /* Generic coprocessor instructions */ + {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"}, + + /* V6 coprocessor instructions */ + {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + + /* V5 coprocessor instructions */ + {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + + {0, 0, 0, 0} +}; + +/* Neon opcode table: This does not encode the top byte -- that is + checked by the print_insn_neon routine, as it depends on whether we are + doing thumb32 or arm32 disassembly. */ + +/* print_insn_neon recognizes the following format control codes: + + %% % + + %c print condition code + %A print v{st,ld}[1234] operands + %B print v{st,ld}[1234] any one operands + %C print v{st,ld}[1234] single->all operands + %D print scalar + %E print vmov, vmvn, vorr, vbic encoded constant + %F print vtbl,vtbx register list + + %r print as an ARM register + %d print the bitfield in decimal + %e print the 2^N - bitfield in decimal + %D print as a NEON D register + %Q print as a NEON Q register + %R print as a NEON D or Q register + %Sn print byte scaled width limited by n + %Tn print short scaled width limited by n + %Un print long scaled width limited by n + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order */ + +static const struct opcode32 neon_opcodes[] = +{ + /* Extract */ + {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + + /* Move data element to all lanes */ + {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"}, + {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"}, + {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"}, + + /* Table lookup */ + {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"}, + + /* Two registers, miscellaneous */ + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"}, + {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, + + /* Three registers of the same length */ + {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + + /* One register and an immediate value */ + {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"}, + + /* Two registers and a shift amount */ + {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"}, + + /* Three registers of different lengths */ + {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + + /* Two registers and a scalar */ + {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + + /* Element and structure load/store */ + {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"}, + + {0,0 ,0, 0} +}; + +/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially + ordered: they must be searched linearly from the top to obtain a correct + match. */ + +/* print_insn_arm recognizes the following format control codes: + + %% % + + %a print address for ldr/str instruction + %s print address for ldr/str halfword/signextend instruction + %b print branch destination + %c print condition code (always bits 28-31) + %m print register mask for ldm/stm instruction + %o print operand2 (immediate or register + shift) + %p print 'p' iff bits 12-15 are 15 + %t print 't' iff bit 21 set and bit 24 clear + %B print arm BLX(1) destination + %C print the PSR sub type. + %U print barrier type. + %P print address for pli instruction. + + %r print as an ARM register + %d print the bitfield in decimal + %W print the bitfield plus one in decimal + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %e print arm SMI operand (bits 0..7,8..19). + %E print the LSB and WIDTH fields of a BFI or BFC instruction. + %V print the 16-bit immediate field of a MOVT or MOVW instruction. */ + +static const struct opcode32 arm_opcodes[] = +{ + /* ARM instructions. */ + {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, + {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, + {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + /* V7 instructions. */ + {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, + {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, + {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, + {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"}, + {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"}, + {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"}, + + /* ARM V6Z instructions. */ + {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"}, + + /* ARM V6K instructions. */ + {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"}, + {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"}, + + /* ARM V6K NOP hints. */ + {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"}, + {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"}, + {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"}, + {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"}, + {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"}, + + /* ARM V6 instructions. */ + {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"}, + {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"}, + {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"}, + {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"}, + {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"}, + {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"}, + + /* V5J instruction. */ + {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, + + /* V5 Instructions. */ + {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, + {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"}, + {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, + {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, + + /* V5E "El Segundo" Instructions. */ + {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"}, + {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, + + /* ARM Instructions. */ + {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, + {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, + {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"}, + {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"}, + {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"}, + {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, + {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"}, + + /* The rest. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"}, + {0, 0x00000000, 0x00000000, 0} +}; + +/* print_insn_thumb16 recognizes the following format control codes: + + %S print Thumb register (bits 3..5 as high number if bit 6 set) + %D print Thumb register (bits 0..2 as high number if bit 7 set) + %I print bitfield as a signed decimal + (top bit of range being the sign bit) + %N print Thumb register mask (with LR) + %O print Thumb register mask (with PC) + %M print Thumb register mask + %b print CZB's 6-bit unsigned branch destination + %s print Thumb right-shift immediate (6..10; 0 == 32). + %c print the condition code + %C print the condition code, or "s" if not conditional + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + %I print IT instruction suffix and operands + %r print bitfield as an ARM register + %d print bitfield as a decimal + %H print (bitfield * 2) as a decimal + %W print (bitfield * 4) as a decimal + %a print (bitfield * 4) as a pc-rel offset + decoded symbol + %B print Thumb branch destination (signed displacement) + %c print bitfield as a condition code + %'c print specified char iff bit is one + %?ab print a if bit is one else print b. */ + +static const struct opcode16 thumb_opcodes[] = +{ + /* Thumb instructions. */ + + /* ARM V6K no-argument instructions. */ + {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, + {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, + {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"}, + {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"}, + {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"}, + {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"}, + + /* ARM V6. */ + {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"}, + {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"}, + + /* ARM V5 ISA extends Thumb. */ + {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional. */ + /* This is BLX(2). BLX(1) is a 32-bit instruction. */ + {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"}, /* note: 4 bit register number. */ + /* ARM V4T ISA (Thumb v1). */ + {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"}, + /* Format 4. */ + {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"}, + /* format 13 */ + {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"}, + {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\tsp, #%0-6W"}, + /* format 5 */ + {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"}, + {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"}, + /* format 14 */ + {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"}, + {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\t%O"}, + /* format 2 */ + {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"}, + {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\t%0-2r, %3-5r, #%6-8d"}, + /* format 8 */ + {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\t%0-2r, [%3-5r, %6-8r]"}, + /* format 7 */ + {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, + /* format 1 */ + {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"}, + {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"}, + {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"}, + /* format 3 */ + {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\t%8-10r, #%0-7d"}, + /* format 6 */ + {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=" */ + /* format 9 */ + {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"}, + {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\t%0-2r, [%3-5r, #%6-10d]"}, + /* format 10 */ + {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"}, + {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\t%0-2r, [%3-5r, #%6-10H]"}, + /* format 11 */ + {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"}, + {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\t%8-10r, [sp, #%0-7W]"}, + /* format 12 */ + {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"}, + {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"}, + /* format 15 */ + {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"}, + {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"}, + /* format 17 */ + {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"}, + /* format 16 */ + {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"}, + {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"}, + /* format 18 */ + {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"}, + + /* The E800 .. FFFF range is unconditionally redirected to the + 32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs + are processed via that table. Thus, we can never encounter a + bare "second half of BL/BLX(1)" instruction here. */ + {ARM_EXT_V1, 0x0000, 0x0000, "undefined"}, + {0, 0, 0, 0} +}; + +/* Thumb32 opcodes use the same table structure as the ARM opcodes. + We adopt the convention that hw1 is the high 16 bits of .value and + .mask, hw2 the low 16 bits. + + print_insn_thumb32 recognizes the following format control codes: + + %% % + + %I print a 12-bit immediate from hw1[10],hw2[14:12,7:0] + %M print a modified 12-bit immediate (same location) + %J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0] + %K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4] + %S print a possibly-shifted Rm + + %a print the address of a plain load/store + %w print the width and signedness of a core load/store + %m print register mask for ldm/stm + + %E print the lsb and width fields of a bfc/bfi instruction + %F print the lsb and width fields of a sbfx/ubfx instruction + %b print a conditional branch offset + %B print an unconditional branch offset + %s print the shift field of an SSAT instruction + %R print the rotation field of an SXT instruction + %U print barrier type. + %P print address for pli instruction. + %c print the condition code + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + + %d print bitfield in decimal + %W print bitfield*4 in decimal + %r print bitfield as an ARM register + %c print bitfield as a condition code + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + With one exception at the bottom (done because BL and BLX(1) need + to come dead last), this table was machine-sorted first in + decreasing order of number of bits set in the mask, then in + increasing numeric order of mask, then in increasing numeric order + of opcode. This order is not the clearest for a human reader, but + is guaranteed never to catch a special-case bit pattern with a more + general mask, which is important, because this instruction encoding + makes heavy use of special-case bit patterns. */ +static const struct opcode32 thumb32_opcodes[] = +{ + /* V7 instructions. */ + {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, + {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, + {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"}, + + /* Instructions defined in the basic V6T2 set. */ + {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"}, + {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"}, + {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"}, + {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"}, + {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"}, + {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"}, + + {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"}, + {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"}, + {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"}, + {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"}, + {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"}, + {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"}, + {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"}, + {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"}, + {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"}, + {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"}, + {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"}, + {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"}, + + /* Filter out Bcc with cond=E or F, which are used for other instructions. */ + {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"}, + {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"}, + {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"}, + {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"}, + + /* These have been 32-bit since the invention of Thumb. */ + {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"}, + {ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"}, + + /* Fallback. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined"}, + {0, 0, 0, 0} +}; + +static const char *const arm_conditional[] = +{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "", ""}; + +static const char *const arm_fp_const[] = +{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; + +static const char *const arm_shift[] = +{"lsl", "lsr", "asr", "ror"}; + +typedef struct +{ + const char *name; + const char *description; + const char *reg_names[16]; +} +arm_regname; + +static const arm_regname regnames[] = +{ + { "raw" , "Select raw register names", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, + { "gcc", "Select register names used by GCC", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, + { "std", "Select register names used in ARM's ISA documentation", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, + { "apcs", "Select register names used in the APCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, + { "atpcs", "Select register names used in the ATPCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, + { "special-atpcs", "Select special register names used in the ATPCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, +}; + +static const char *const iwmmxt_wwnames[] = +{"b", "h", "w", "d"}; + +static const char *const iwmmxt_wwssnames[] = +{"b", "bus", "bc", "bss", + "h", "hus", "hc", "hss", + "w", "wus", "wc", "wss", + "d", "dus", "dc", "dss" +}; + +static const char *const iwmmxt_regnames[] = +{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", + "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15" +}; + +static const char *const iwmmxt_cregnames[] = +{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", + "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved" +}; + +/* Default to GCC register name set. */ +static unsigned int regname_selected = 1; + +#define NUM_ARM_REGNAMES NUM_ELEM (regnames) +#define arm_regnames regnames[regname_selected].reg_names + +static bfd_boolean force_thumb = false; + +/* Current IT instruction state. This contains the same state as the IT + bits in the CPSR. */ +static unsigned int ifthen_state; +/* IT state for the next instruction. */ +static unsigned int ifthen_next_state; +/* The address of the insn for which the IT state is valid. */ +static bfd_vma ifthen_address; +#define IFTHEN_COND ((ifthen_state >> 4) & 0xf) + +/* Cached mapping symbol state. */ +enum map_type { + MAP_ARM, + MAP_THUMB, + MAP_DATA +}; + +enum map_type last_type; +int last_mapping_sym = -1; +bfd_vma last_mapping_addr = 0; + +/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?. + Returns pointer to following character of the format string and + fills in *VALUEP and *WIDTHP with the extracted value and number of + bits extracted. WIDTHP can be NULL. */ + +static const char * +arm_decode_bitfield (const char *ptr, unsigned long insn, + unsigned long *valuep, int *widthp) +{ + unsigned long value = 0; + int width = 0; + + do + { + int start, end; + int bits; + + for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++) + start = start * 10 + *ptr - '0'; + if (*ptr == '-') + for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++) + end = end * 10 + *ptr - '0'; + else + end = start; + bits = end - start; + if (bits < 0) + abort (); + value |= ((insn >> start) & ((2ul << bits) - 1)) << width; + width += bits + 1; + } + while (*ptr++ == ','); + *valuep = value; + if (widthp) + *widthp = width; + return ptr - 1; +} + +static void +arm_decode_shift (long given, fprintf_ftype func, void *stream, + int print_shift) +{ + func (stream, "%s", arm_regnames[given & 0xf]); + + if ((given & 0xff0) != 0) + { + if ((given & 0x10) == 0) + { + int amount = (given & 0xf80) >> 7; + int shift = (given & 0x60) >> 5; + + if (amount == 0) + { + if (shift == 3) + { + func (stream, ", rrx"); + return; + } + + amount = 32; + } + + if (print_shift) + func (stream, ", %s #%d", arm_shift[shift], amount); + else + func (stream, ", #%d", amount); + } + else if (print_shift) + func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], + arm_regnames[(given & 0xf00) >> 8]); + else + func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]); + } +} + +/* Print one coprocessor instruction on INFO->STREAM. + Return true if the instuction matched, false if this is not a + recognised coprocessor instruction. */ + +static bfd_boolean +print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, + bfd_boolean thumb) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + unsigned long mask; + unsigned long value; + int cond; + + for (insn = coprocessor_opcodes; insn->assembler; insn++) + { + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt + && info->mach != bfd_mach_arm_iWMMXt2) + insn = insn + IWMMXT_INSN_COUNT; + + mask = insn->mask; + value = insn->value; + if (thumb) + { + /* The high 4 bits are 0xe for Arm conditional instructions, and + 0xe for arm unconditional instructions. The rest of the + encoding is the same. */ + mask |= 0xf0000000; + value |= 0xe0000000; + if (ifthen_state) + cond = IFTHEN_COND; + else + cond = 16; + } + else + { + /* Only match unconditional instuctions against unconditional + patterns. */ + if ((given & 0xf0000000) == 0xf0000000) + { + mask |= 0xf0000000; + cond = 16; + } + else + { + cond = (given >> 28) & 0xf; + if (cond == 0xe) + cond = 16; + } + } + if ((given & mask) == value) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'A': + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if ((given & (1 << 24)) != 0) + { + int offset = given & 0xff; + + if (offset) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "]"); + } + else + { + int offset = given & 0xff; + + func (stream, "]"); + + if (given & (1 << 21)) + { + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); + } + else + func (stream, ", {%d}", offset); + } + break; + + case 'B': + { + int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10); + int offset = (given >> 1) & 0x3f; + + if (offset == 1) + func (stream, "{d%d}", regno); + else if (regno + offset > 32) + func (stream, "{d%d-}", regno, regno + offset - 1); + else + func (stream, "{d%d-d%d}", regno, regno + offset - 1); + } + break; + + case 'C': + { + int rn = (given >> 16) & 0xf; + int offset = (given & 0xff) * 4; + int add = (given >> 23) & 1; + + func (stream, "[%s", arm_regnames[rn]); + + if (offset) + { + if (!add) + offset = -offset; + func (stream, ", #%d", offset); + } + func (stream, "]"); + if (rn == 15) + { + func (stream, "\t; "); + /* FIXME: Unsure if info->bytes_per_chunk is the + right thing to use here. */ + info->print_address_func (offset + pc + + info->bytes_per_chunk * 2, info); + } + } + break; + + case 'c': + func (stream, "%s", arm_conditional[cond]); + break; + + case 'I': + /* Print a Cirrus/DSP shift immediate. */ + /* Immediates are 7bit signed ints with bits 0..3 in + bits 0..3 of opcode and bits 4..6 in bits 5..7 + of opcode. */ + { + int imm; + + imm = (given & 0xf) | ((given & 0xe0) >> 1); + + /* Is ``imm'' a negative number? */ + if (imm & 0x40) + imm |= (-1 << 7); + + func (stream, "%d", imm); + } + + break; + + case 'F': + switch (given & 0x00408000) + { + case 0: + func (stream, "4"); + break; + case 0x8000: + func (stream, "1"); + break; + case 0x00400000: + func (stream, "2"); + break; + default: + func (stream, "3"); + } + break; + + case 'P': + switch (given & 0x00080080) + { + case 0: + func (stream, "s"); + break; + case 0x80: + func (stream, "d"); + break; + case 0x00080000: + func (stream, "e"); + break; + default: + func (stream, _("")); + break; + } + break; + case 'Q': + switch (given & 0x00408000) + { + case 0: + func (stream, "s"); + break; + case 0x8000: + func (stream, "d"); + break; + case 0x00400000: + func (stream, "e"); + break; + default: + func (stream, "p"); + break; + } + break; + case 'R': + switch (given & 0x60) + { + case 0: + break; + case 0x20: + func (stream, "p"); + break; + case 0x40: + func (stream, "m"); + break; + default: + func (stream, "z"); + break; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); + + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'k': + { + int from = (given & (1 << 7)) ? 32 : 16; + func (stream, "%ld", from - value); + } + break; + + case 'f': + if (value > 7) + func (stream, "#%s", arm_fp_const[value & 7]); + else + func (stream, "f%ld", value); + break; + + case 'w': + if (width == 2) + func (stream, "%s", iwmmxt_wwnames[value]); + else + func (stream, "%s", iwmmxt_wwssnames[value]); + break; + + case 'g': + func (stream, "%s", iwmmxt_regnames[value]); + break; + case 'G': + func (stream, "%s", iwmmxt_cregnames[value]); + break; + + case 'x': + func (stream, "0x%lx", value); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + case 'y': + case 'z': + { + int single = *c++ == 'y'; + int regno; + + switch (*c) + { + case '4': /* Sm pair */ + func (stream, "{"); + /* Fall through. */ + case '0': /* Sm, Dm */ + regno = given & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 5) & 1; + } + else + regno += ((given >> 5) & 1) << 4; + break; + + case '1': /* Sd, Dd */ + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; + + case '2': /* Sn, Dn */ + regno = (given >> 16) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 7) & 1; + } + else + regno += ((given >> 7) & 1) << 4; + break; + + case '3': /* List */ + func (stream, "{"); + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; + + default: + abort (); + } + + func (stream, "%c%d", single ? 's' : 'd', regno); + + if (*c == '3') + { + int count = given & 0xff; + + if (single == 0) + count >>= 1; + + if (--count) + { + func (stream, "-%c%d", + single ? 's' : 'd', + regno + count); + } + + func (stream, "}"); + } + else if (*c == '4') + func (stream, ", %c%d}", single ? 's' : 'd', + regno + 1); + } + break; + + case 'L': + switch (given & 0x00400100) + { + case 0x00000000: func (stream, "b"); break; + case 0x00400000: func (stream, "h"); break; + case 0x00000100: func (stream, "w"); break; + case 0x00400100: func (stream, "d"); break; + default: + break; + } + break; + + case 'Z': + { + int value; + /* given (20, 23) | given (0, 3) */ + value = ((given >> 16) & 0xf0) | (given & 0xf); + func (stream, "%d", value); + } + break; + + case 'l': + /* This is like the 'A' operator, except that if + the width field "M" is zero, then the offset is + *not* multiplied by four. */ + { + int offset = given & 0xff; + int multiplier = (given & 0x00000100) ? 4 : 1; + + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if (offset) + { + if ((given & 0x01000000) != 0) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "], #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier); + } + else + func (stream, "]"); + } + break; + + case 'r': + { + int imm4 = (given >> 4) & 0xf; + int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1); + int ubit = (given >> 23) & 1; + const char *rm = arm_regnames [given & 0xf]; + const char *rn = arm_regnames [(given >> 16) & 0xf]; + + switch (puw_bits) + { + case 1: + /* fall through */ + case 3: + func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm); + if (imm4) + func (stream, ", lsl #%d", imm4); + break; + + case 4: + /* fall through */ + case 5: + /* fall through */ + case 6: + /* fall through */ + case 7: + func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm); + if (imm4 > 0) + func (stream, ", lsl #%d", imm4); + func (stream, "]"); + if (puw_bits == 5 || puw_bits == 7) + func (stream, "!"); + break; + + default: + func (stream, "INVALID"); + } + } + break; + + case 'i': + { + long imm5; + imm5 = ((given & 0x100) >> 4) | (given & 0xf); + func (stream, "%ld", (imm5 == 0) ? 32 : imm5); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return true; + } + } + return false; +} + +static void +print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) +{ + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (((given & 0x000f0000) == 0x000f0000) + && ((given & 0x02000000) == 0)) + { + int offset = given & 0xfff; + + func (stream, "[pc"); + + if (given & 0x01000000) + { + if ((given & 0x00800000) == 0) + offset = - offset; + + /* Pre-indexed. */ + func (stream, ", #%d]", offset); + + offset += pc + 8; + + /* Cope with the possibility of write-back + being used. Probably a very dangerous thing + for the programmer to do, but who are we to + argue ? */ + if (given & 0x00200000) + func (stream, "!"); + } + else + { + /* Post indexed. */ + func (stream, "], #%d", offset); + + /* ie ignore the offset. */ + offset = pc + 8; + } + + func (stream, "\t; "); + info->print_address_func (offset, info); + } + else + { + func (stream, "[%s", + arm_regnames[(given >> 16) & 0xf]); + if ((given & 0x01000000) != 0) + { + if ((given & 0x02000000) == 0) + { + int offset = given & 0xfff; + if (offset) + func (stream, ", #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + } + else + { + func (stream, ", %s", + (((given & 0x00800000) == 0) + ? "-" : "")); + arm_decode_shift (given, func, stream, 1); + } + + func (stream, "]%s", + ((given & 0x00200000) != 0) ? "!" : ""); + } + else + { + if ((given & 0x02000000) == 0) + { + int offset = given & 0xfff; + if (offset) + func (stream, "], #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + else + func (stream, "]"); + } + else + { + func (stream, "], %s", + (((given & 0x00800000) == 0) + ? "-" : "")); + arm_decode_shift (given, func, stream, 1); + } + } + } +} + +/* Print one neon instruction on INFO->STREAM. + Return true if the instuction matched, false if this is not a + recognised neon instruction. */ + +static bfd_boolean +print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (thumb) + { + if ((given & 0xef000000) == 0xef000000) + { + /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding. */ + unsigned long bit28 = given & (1 << 28); + + given &= 0x00ffffff; + if (bit28) + given |= 0xf3000000; + else + given |= 0xf2000000; + } + else if ((given & 0xff000000) == 0xf9000000) + given ^= 0xf9000000 ^ 0xf4000000; + else + return false; + } + + for (insn = neon_opcodes; insn->assembler; insn++) + { + if ((given & insn->mask) == insn->value) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (thumb && ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'A': + { + static const unsigned char enc[16] = + { + 0x4, 0x14, /* st4 0,1 */ + 0x4, /* st1 2 */ + 0x4, /* st2 3 */ + 0x3, /* st3 4 */ + 0x13, /* st3 5 */ + 0x3, /* st1 6 */ + 0x1, /* st1 7 */ + 0x2, /* st2 8 */ + 0x12, /* st2 9 */ + 0x2, /* st1 10 */ + 0, 0, 0, 0, 0 + }; + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x3); + int type = ((given >> 8) & 0xf); + int n = enc[type] & 0xf; + int stride = (enc[type] >> 4) + 1; + int ix; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d", rd); + else + func (stream, "d%d-d%d", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", 32 << align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'B': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int idx_align = ((given >> 4) & 0xf); + int align = 0; + int size = ((given >> 10) & 0x3); + int idx = idx_align >> (size + 1); + int length = ((given >> 8) & 3) + 1; + int stride = 1; + int i; + + if (length > 1 && size > 0) + stride = (idx_align & (1 << size)) ? 2 : 1; + + switch (length) + { + case 1: + { + int amask = (1 << size) - 1; + if ((idx_align & (1 << size)) != 0) + return false; + if (size > 0) + { + if ((idx_align & amask) == amask) + align = 8 << size; + else if ((idx_align & amask) != 0) + return false; + } + } + break; + + case 2: + if (size == 2 && (idx_align & 2) != 0) + return false; + align = (idx_align & 1) ? 16 << size : 0; + break; + + case 3: + if ((size == 2 && (idx_align & 3) != 0) + || (idx_align & 1) != 0) + return false; + break; + + case 4: + if (size == 2) + { + if ((idx_align & 3) == 3) + return false; + align = (idx_align & 3) * 64; + } + else + align = (idx_align & 1) ? 32 << size : 0; + break; + + default: + abort (); + } + + func (stream, "{"); + for (i = 0; i < length; i++) + func (stream, "%sd%d[%d]", (i == 0) ? "" : ",", + rd + i * stride, idx); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'C': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x1); + int size = ((given >> 6) & 0x3); + int type = ((given >> 8) & 0x3); + int n = type + 1; + int stride = ((given >> 5) & 0x1); + int ix; + + if (stride && (n == 1)) + n++; + else + stride++; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d[]", rd); + else + func (stream, "d%d[]-d%d[]", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + { + int align = (8 * (type + 1)) << size; + if (type == 3) + align = (size > 1) ? align >> 1 : align; + if (type == 2 || (type == 0 && !size)) + func (stream, ", :", align); + else + func (stream, ", :%d", align); + } + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'D': + { + int raw_reg = (given & 0xf) | ((given >> 1) & 0x10); + int size = (given >> 20) & 3; + int reg = raw_reg & ((4 << size) - 1); + int ix = raw_reg >> size >> 2; + + func (stream, "d%d[%d]", reg, ix); + } + break; + + case 'E': + /* Neon encoded constant for mov, mvn, vorr, vbic */ + { + int bits = 0; + int cmode = (given >> 8) & 0xf; + int op = (given >> 5) & 0x1; + unsigned long value = 0, hival = 0; + unsigned shift; + int size = 0; + int isfloat = 0; + + bits |= ((given >> 24) & 1) << 7; + bits |= ((given >> 16) & 7) << 4; + bits |= ((given >> 0) & 15) << 0; + + if (cmode < 8) + { + shift = (cmode >> 1) & 3; + value = (unsigned long)bits << (8 * shift); + size = 32; + } + else if (cmode < 12) + { + shift = (cmode >> 1) & 1; + value = (unsigned long)bits << (8 * shift); + size = 16; + } + else if (cmode < 14) + { + shift = (cmode & 1) + 1; + value = (unsigned long)bits << (8 * shift); + value |= (1ul << (8 * shift)) - 1; + size = 32; + } + else if (cmode == 14) + { + if (op) + { + /* bit replication into bytes */ + int ix; + unsigned long mask; + + value = 0; + hival = 0; + for (ix = 7; ix >= 0; ix--) + { + mask = ((bits >> ix) & 1) ? 0xff : 0; + if (ix <= 3) + value = (value << 8) | mask; + else + hival = (hival << 8) | mask; + } + size = 64; + } + else + { + /* byte replication */ + value = (unsigned long)bits; + size = 8; + } + } + else if (!op) + { + /* floating point encoding */ + int tmp; + + value = (unsigned long)(bits & 0x7f) << 19; + value |= (unsigned long)(bits & 0x80) << 24; + tmp = bits & 0x40 ? 0x3c : 0x40; + value |= (unsigned long)tmp << 24; + size = 32; + isfloat = 1; + } + else + { + func (stream, "", + bits, cmode, op); + size = 32; + break; + } + switch (size) + { + case 8: + func (stream, "#%ld\t; 0x%.2lx", value, value); + break; + + case 16: + func (stream, "#%ld\t; 0x%.4lx", value, value); + break; + + case 32: + if (isfloat) + { + unsigned char valbytes[4]; + double fvalue; + + /* Do this a byte at a time so we don't have to + worry about the host's endianness. */ + valbytes[0] = value & 0xff; + valbytes[1] = (value >> 8) & 0xff; + valbytes[2] = (value >> 16) & 0xff; + valbytes[3] = (value >> 24) & 0xff; + + floatformat_to_double + (&floatformat_ieee_single_little, valbytes, + &fvalue); + + func (stream, "#%.7g\t; 0x%.8lx", fvalue, + value); + } + else + func (stream, "#%ld\t; 0x%.8lx", + (long) ((value & 0x80000000) + ? value | ~0xffffffffl : value), value); + break; + + case 64: + func (stream, "#0x%.8lx%.8lx", hival, value); + break; + + default: + abort (); + } + } + break; + + case 'F': + { + int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10); + int num = (given >> 8) & 0x3; + + if (!num) + func (stream, "{d%d}", regno); + else if (num + regno >= 32) + func (stream, "{d%d-= '0' && *c <= '9') + limit = *c - '0'; + else if (*c >= 'a' && *c <= 'f') + limit = *c - 'a' + 10; + else + abort (); + low = limit >> 2; + high = limit & 3; + + if (value < low || value > high) + func (stream, "", base << value); + else + func (stream, "%d", base << value); + } + break; + case 'R': + if (given & (1 << 6)) + goto Q; + /* FALLTHROUGH */ + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + Q: + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return true; + } + } + return false; +} + +/* Print one ARM instruction from PC on INFO->STREAM. */ + +static void +print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (print_insn_coprocessor (pc, info, given, false)) + return; + + if (print_insn_neon (info, given, false)) + return; + + for (insn = arm_opcodes; insn->assembler; insn++) + { + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt) + insn = insn + IWMMXT_INSN_COUNT; + + if ((given & insn->mask) == insn->value + /* Special case: an instruction with all bits set in the condition field + (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask, + or by the catchall at the end of the table. */ + && ((given & 0xF0000000) != 0xF0000000 + || (insn->mask & 0xF0000000) == 0xF0000000 + || (insn->mask == 0 && insn->value == 0))) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'a': + print_arm_address (pc, info, given); + break; + + case 'P': + /* Set P address bit and use normal address + printing routine. */ + print_arm_address (pc, info, given | (1 << 24)); + break; + + case 's': + if ((given & 0x004f0000) == 0x004f0000) + { + /* PC relative with immediate offset. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + + if ((given & 0x00800000) == 0) + offset = -offset; + + func (stream, "[pc, #%d]\t; ", offset); + info->print_address_func (offset + pc + 8, info); + } + else + { + func (stream, "[%s", + arm_regnames[(given >> 16) & 0xf]); + if ((given & 0x01000000) != 0) + { + /* Pre-indexed. */ + if ((given & 0x00400000) == 0x00400000) + { + /* Immediate. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + if (offset) + func (stream, ", #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + } + else + { + /* Register. */ + func (stream, ", %s%s", + (((given & 0x00800000) == 0) + ? "-" : ""), + arm_regnames[given & 0xf]); + } + + func (stream, "]%s", + ((given & 0x00200000) != 0) ? "!" : ""); + } + else + { + /* Post-indexed. */ + if ((given & 0x00400000) == 0x00400000) + { + /* Immediate. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + if (offset) + func (stream, "], #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + else + func (stream, "]"); + } + else + { + /* Register. */ + func (stream, "], %s%s", + (((given & 0x00800000) == 0) + ? "-" : ""), + arm_regnames[given & 0xf]); + } + } + } + break; + + case 'b': + { + int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000); + info->print_address_func (disp*4 + pc + 8, info); + } + break; + + case 'c': + if (((given >> 28) & 0xf) != 0xe) + func (stream, "%s", + arm_conditional [(given >> 28) & 0xf]); + break; + + case 'm': + { + int started = 0; + int reg; + + func (stream, "{"); + for (reg = 0; reg < 16; reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + func (stream, "}"); + } + break; + + case 'q': + arm_decode_shift (given, func, stream, 0); + break; + + case 'o': + if ((given & 0x02000000) != 0) + { + int rotate = (given & 0xf00) >> 7; + int immed = (given & 0xff); + immed = (((immed << (32 - rotate)) + | (immed >> rotate)) & 0xffffffff); + func (stream, "#%d\t; 0x%x", immed, immed); + } + else + arm_decode_shift (given, func, stream, 1); + break; + + case 'p': + if ((given & 0x0000f000) == 0x0000f000) + func (stream, "p"); + break; + + case 't': + if ((given & 0x01200000) == 0x00200000) + func (stream, "t"); + break; + + case 'A': + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if ((given & (1 << 24)) != 0) + { + int offset = given & 0xff; + + if (offset) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "]"); + } + else + { + int offset = given & 0xff; + + func (stream, "]"); + + if (given & (1 << 21)) + { + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); + } + else + func (stream, ", {%d}", offset); + } + break; + + case 'B': + /* Print ARM V5 BLX(1) address: pc+25 bits. */ + { + bfd_vma address; + bfd_vma offset = 0; + + if (given & 0x00800000) + /* Is signed, hi bits should be ones. */ + offset = (-1) ^ 0x00ffffff; + + /* Offset is (SignExtend(offset field)<<2). */ + offset += given & 0x00ffffff; + offset <<= 2; + address = offset + pc + 8; + + if (given & 0x01000000) + /* H bit allows addressing to 2-byte boundaries. */ + address += 2; + + info->print_address_func (address, info); + } + break; + + case 'C': + func (stream, "_"); + if (given & 0x80000) + func (stream, "f"); + if (given & 0x40000) + func (stream, "s"); + if (given & 0x20000) + func (stream, "x"); + if (given & 0x10000) + func (stream, "c"); + break; + + case 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); + + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'b': + func (stream, "%ld", value * 8); + break; + case 'W': + func (stream, "%ld", value + 1); + break; + case 'x': + func (stream, "0x%08lx", value); + + /* Some SWI instructions have special + meanings. */ + if ((given & 0x0fffffff) == 0x0FF00000) + func (stream, "\t; IMB"); + else if ((given & 0x0fffffff) == 0x0FF00001) + func (stream, "\t; IMBRange"); + break; + case 'X': + func (stream, "%01lx", value & 0xf); + break; + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + case 'e': + { + int imm; + + imm = (given & 0xf) | ((given & 0xfff00) >> 4); + func (stream, "%d", imm); + } + break; + + case 'E': + /* LSB and WIDTH fields of BFI or BFC. The machine- + language instruction encodes LSB and MSB. */ + { + long msb = (given & 0x001f0000) >> 16; + long lsb = (given & 0x00000f80) >> 7; + + long width = msb - lsb + 1; + if (width > 0) + func (stream, "#%lu, #%lu", lsb, width); + else + func (stream, "(invalid: %lu:%lu)", lsb, msb); + } + break; + + case 'V': + /* 16-bit unsigned immediate from a MOVT or MOVW + instruction, encoded in bits 0:11 and 15:19. */ + { + long hi = (given & 0x000f0000) >> 4; + long lo = (given & 0x00000fff); + long imm16 = hi | lo; + func (stream, "#%lu\t; 0x%lx", imm16, imm16); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return; + } + } + abort (); +} + +/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */ + +static void +print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode16 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + for (insn = thumb_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) + { + int domaskpc = 0; + int domasklr = 0; + + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'C': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + else + func (stream, "s"); + break; + + case 'I': + { + unsigned int tmp; + + ifthen_next_state = given & 0xff; + for (tmp = given << 1; tmp & 0xf; tmp <<= 1) + func (stream, ((given ^ tmp) & 0x10) ? "e" : "t"); + func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]); + } + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + break; + + case 'S': + { + long reg; + + reg = (given >> 3) & 0x7; + if (given & (1 << 6)) + reg += 8; + + func (stream, "%s", arm_regnames[reg]); + } + break; + + case 'D': + { + long reg; + + reg = given & 0x7; + if (given & (1 << 7)) + reg += 8; + + func (stream, "%s", arm_regnames[reg]); + } + break; + + case 'N': + if (given & (1 << 8)) + domasklr = 1; + /* Fall through. */ + case 'O': + if (*c == 'O' && (given & (1 << 8))) + domaskpc = 1; + /* Fall through. */ + case 'M': + { + int started = 0; + int reg; + + func (stream, "{"); + + /* It would be nice if we could spot + ranges, and generate the rS-rE format: */ + for (reg = 0; (reg < 8); reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + + if (domasklr) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, arm_regnames[14] /* "lr" */); + } + + if (domaskpc) + { + if (started) + func (stream, ", "); + func (stream, arm_regnames[15] /* "pc" */); + } + + func (stream, "}"); + } + break; + + case 'b': + /* Print ARM V6T2 CZB address: pc+4+6 bits. */ + { + bfd_vma address = (pc + 4 + + ((given & 0x00f8) >> 2) + + ((given & 0x0200) >> 3)); + info->print_address_func (address, info); + } + break; + + case 's': + /* Right shift immediate -- bits 6..10; 1-31 print + as themselves, 0 prints as 32. */ + { + long imm = (given & 0x07c0) >> 6; + if (imm == 0) + imm = 32; + func (stream, "#%ld", imm); + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int bitstart = *c++ - '0'; + int bitend = 0; + + while (*c >= '0' && *c <= '9') + bitstart = (bitstart * 10) + *c++ - '0'; + + switch (*c) + { + case '-': + { + long reg; + + c++; + while (*c >= '0' && *c <= '9') + bitend = (bitend * 10) + *c++ - '0'; + if (!bitend) + abort (); + reg = given >> bitstart; + reg &= (2 << (bitend - bitstart)) - 1; + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[reg]); + break; + + case 'd': + func (stream, "%ld", reg); + break; + + case 'H': + func (stream, "%ld", reg << 1); + break; + + case 'W': + func (stream, "%ld", reg << 2); + break; + + case 'a': + /* PC-relative address -- the bottom two + bits of the address are dropped + before the calculation. */ + info->print_address_func + (((pc + 4) & ~3) + (reg << 2), info); + break; + + case 'x': + func (stream, "0x%04lx", reg); + break; + + case 'B': + reg = ((reg ^ (1 << bitend)) - (1 << bitend)); + info->print_address_func (reg * 2 + pc + 4, info); + break; + + case 'c': + func (stream, "%s", arm_conditional [reg]); + break; + + default: + abort (); + } + } + break; + + case '\'': + c++; + if ((given & (1 << bitstart)) != 0) + func (stream, "%c", *c); + break; + + case '?': + ++c; + if ((given & (1 << bitstart)) != 0) + func (stream, "%c", *c++); + else + func (stream, "%c", *++c); + break; + + default: + abort (); + } + } + break; + + default: + abort (); + } + } + return; + } + + /* No match. */ + abort (); +} + +/* Return the name of an V7M special register. */ +static const char * +psr_name (int regno) +{ + switch (regno) + { + case 0: return "APSR"; + case 1: return "IAPSR"; + case 2: return "EAPSR"; + case 3: return "PSR"; + case 5: return "IPSR"; + case 6: return "EPSR"; + case 7: return "IEPSR"; + case 8: return "MSP"; + case 9: return "PSP"; + case 16: return "PRIMASK"; + case 17: return "BASEPRI"; + case 18: return "BASEPRI_MASK"; + case 19: return "FAULTMASK"; + case 20: return "CONTROL"; + default: return ""; + } +} + +/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */ + +static void +print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (print_insn_coprocessor (pc, info, given, true)) + return; + + if (print_insn_neon (info, given, true)) + return; + + for (insn = thumb32_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) + { + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + break; + + case 'I': + { + unsigned int imm12 = 0; + imm12 |= (given & 0x000000ffu); + imm12 |= (given & 0x00007000u) >> 4; + imm12 |= (given & 0x04000000u) >> 15; + func (stream, "#%u\t; 0x%x", imm12, imm12); + } + break; + + case 'M': + { + unsigned int bits = 0, imm, imm8, mod; + bits |= (given & 0x000000ffu); + bits |= (given & 0x00007000u) >> 4; + bits |= (given & 0x04000000u) >> 15; + imm8 = (bits & 0x0ff); + mod = (bits & 0xf00) >> 8; + switch (mod) + { + case 0: imm = imm8; break; + case 1: imm = ((imm8<<16) | imm8); break; + case 2: imm = ((imm8<<24) | (imm8 << 8)); break; + case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break; + default: + mod = (bits & 0xf80) >> 7; + imm8 = (bits & 0x07f) | 0x80; + imm = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff); + } + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'J': + { + unsigned int imm = 0; + imm |= (given & 0x000000ffu); + imm |= (given & 0x00007000u) >> 4; + imm |= (given & 0x04000000u) >> 15; + imm |= (given & 0x000f0000u) >> 4; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'K': + { + unsigned int imm = 0; + imm |= (given & 0x000f0000u) >> 16; + imm |= (given & 0x00000ff0u) >> 0; + imm |= (given & 0x0000000fu) << 12; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'S': + { + unsigned int reg = (given & 0x0000000fu); + unsigned int stp = (given & 0x00000030u) >> 4; + unsigned int imm = 0; + imm |= (given & 0x000000c0u) >> 6; + imm |= (given & 0x00007000u) >> 10; + + func (stream, "%s", arm_regnames[reg]); + switch (stp) + { + case 0: + if (imm > 0) + func (stream, ", lsl #%u", imm); + break; + + case 1: + if (imm == 0) + imm = 32; + func (stream, ", lsr #%u", imm); + break; + + case 2: + if (imm == 0) + imm = 32; + func (stream, ", asr #%u", imm); + break; + + case 3: + if (imm == 0) + func (stream, ", rrx"); + else + func (stream, ", ror #%u", imm); + } + } + break; + + case 'a': + { + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int op = (given & 0x00000f00) >> 8; + unsigned int i12 = (given & 0x00000fff); + unsigned int i8 = (given & 0x000000ff); + bfd_boolean writeback = false, postind = false; + int offset = 0; + + func (stream, "[%s", arm_regnames[Rn]); + if (U) /* 12-bit positive immediate offset */ + offset = i12; + else if (Rn == 15) /* 12-bit negative immediate offset */ + offset = -(int)i12; + else if (op == 0x0) /* shifted register offset */ + { + unsigned int Rm = (i8 & 0x0f); + unsigned int sh = (i8 & 0x30) >> 4; + func (stream, ", %s", arm_regnames[Rm]); + if (sh) + func (stream, ", lsl #%u", sh); + func (stream, "]"); + break; + } + else switch (op) + { + case 0xE: /* 8-bit positive immediate offset */ + offset = i8; + break; + + case 0xC: /* 8-bit negative immediate offset */ + offset = -i8; + break; + + case 0xF: /* 8-bit + preindex with wb */ + offset = i8; + writeback = true; + break; + + case 0xD: /* 8-bit - preindex with wb */ + offset = -i8; + writeback = true; + break; + + case 0xB: /* 8-bit + postindex */ + offset = i8; + postind = true; + break; + + case 0x9: /* 8-bit - postindex */ + offset = -i8; + postind = true; + break; + + default: + func (stream, ", ]"); + goto skip; + } + + if (postind) + func (stream, "], #%d", offset); + else + { + if (offset) + func (stream, ", #%d", offset); + func (stream, writeback ? "]!" : "]"); + } + + if (Rn == 15) + { + func (stream, "\t; "); + info->print_address_func (((pc + 4) & ~3) + offset, info); + } + } + skip: + break; + + case 'A': + { + unsigned int P = (given & 0x01000000) >> 24; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int W = (given & 0x00400000) >> 21; + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int off = (given & 0x000000ff); + + func (stream, "[%s", arm_regnames[Rn]); + if (P) + { + if (off || !U) + func (stream, ", #%c%u", U ? '+' : '-', off * 4); + func (stream, "]"); + if (W) + func (stream, "!"); + } + else + { + func (stream, "], "); + if (W) + func (stream, "#%c%u", U ? '+' : '-', off * 4); + else + func (stream, "{%u}", off); + } + } + break; + + case 'w': + { + unsigned int Sbit = (given & 0x01000000) >> 24; + unsigned int type = (given & 0x00600000) >> 21; + switch (type) + { + case 0: func (stream, Sbit ? "sb" : "b"); break; + case 1: func (stream, Sbit ? "sh" : "h"); break; + case 2: + if (Sbit) + func (stream, "??"); + break; + case 3: + func (stream, "??"); + break; + } + } + break; + + case 'm': + { + int started = 0; + int reg; + + func (stream, "{"); + for (reg = 0; reg < 16; reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + func (stream, "}"); + } + break; + + case 'E': + { + unsigned int msb = (given & 0x0000001f); + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, msb - lsb + 1); + } + break; + + case 'F': + { + unsigned int width = (given & 0x0000001f) + 1; + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, width); + } + break; + + case 'b': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int J1 = (given & 0x00002000u) >> 13; + unsigned int J2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 20; + offset |= J2 << 19; + offset |= J1 << 18; + offset |= (given & 0x003f0000) >> 4; + offset |= (given & 0x000007ff) << 1; + offset -= (1 << 20); + + info->print_address_func (pc + 4 + offset, info); + } + break; + + case 'B': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int I1 = (given & 0x00002000u) >> 13; + unsigned int I2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 24; + offset |= !(I1 ^ S) << 23; + offset |= !(I2 ^ S) << 22; + offset |= (given & 0x03ff0000u) >> 4; + offset |= (given & 0x000007ffu) << 1; + offset -= (1 << 24); + offset += pc + 4; + + /* BLX target addresses are always word aligned. */ + if ((given & 0x00001000u) == 0) + offset &= ~2u; + + info->print_address_func (offset, info); + } + break; + + case 's': + { + unsigned int shift = 0; + shift |= (given & 0x000000c0u) >> 6; + shift |= (given & 0x00007000u) >> 10; + if (given & 0x00200000u) + func (stream, ", asr #%u", shift); + else if (shift) + func (stream, ", lsl #%u", shift); + /* else print nothing - lsl #0 */ + } + break; + + case 'R': + { + unsigned int rot = (given & 0x00000030) >> 4; + if (rot) + func (stream, ", ror #%u", rot * 8); + } + break; + + case 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case 'C': + if ((given & 0xff) == 0) + { + func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C'); + if (given & 0x800) + func (stream, "f"); + if (given & 0x400) + func (stream, "s"); + if (given & 0x200) + func (stream, "x"); + if (given & 0x100) + func (stream, "c"); + } + else + { + func (stream, psr_name (given & 0xff)); + } + break; + + case 'D': + if ((given & 0xff) == 0) + func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); + else + func (stream, psr_name (given & 0xff)); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long val; + + c = arm_decode_bitfield (c, given, &val, &width); + + switch (*c) + { + case 'd': func (stream, "%lu", val); break; + case 'W': func (stream, "%lu", val * 4); break; + case 'r': func (stream, "%s", arm_regnames[val]); break; + + case 'c': + func (stream, "%s", arm_conditional[val]); + break; + + case '\'': + c++; + if (val == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + + case '`': + c++; + if (val == 0) + func (stream, "%c", *c); + break; + + case '?': + func (stream, "%c", c[(1 << width) - (int)val]); + c += 1 << width; + break; + + default: + abort (); + } + } + break; + + default: + abort (); + } + } + return; + } + + /* No match. */ + abort (); +} + +/* Print data bytes on INFO->STREAM. */ + +static void +print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info, + long given) +{ + switch (info->bytes_per_chunk) + { + case 1: + info->fprintf_func (info->stream, ".byte\t0x%02lx", given); + break; + case 2: + info->fprintf_func (info->stream, ".short\t0x%04lx", given); + break; + case 4: + info->fprintf_func (info->stream, ".word\t0x%08lx", given); + break; + default: + abort (); + } +} + +/* Search back through the insn stream to determine if this instruction is + conditionally executed. */ +static void +find_ifthen_state (bfd_vma pc, struct disassemble_info *info, + bfd_boolean little) +{ + unsigned char b[2]; + unsigned int insn; + int status; + /* COUNT is twice the number of instructions seen. It will be odd if we + just crossed an instruction boundary. */ + int count; + int it_count; + unsigned int seen_it; + bfd_vma addr; + + ifthen_address = pc; + ifthen_state = 0; + + addr = pc; + count = 1; + it_count = 0; + seen_it = 0; + /* Scan backwards looking for IT instructions, keeping track of where + instruction boundaries are. We don't know if something is actually an + IT instruction until we find a definite instruction boundary. */ + for (;;) + { + if (addr == 0 || info->symbol_at_address_func(addr, info)) + { + /* A symbol must be on an instruction boundary, and will not + be within an IT block. */ + if (seen_it && (count & 1)) + break; + + return; + } + addr -= 2; + status = info->read_memory_func (addr, (bfd_byte *)b, 2, info); + if (status) + return; + + if (little) + insn = (b[0]) | (b[1] << 8); + else + insn = (b[1]) | (b[0] << 8); + if (seen_it) + { + if ((insn & 0xf800) < 0xe800) + { + /* Addr + 2 is an instruction boundary. See if this matches + the expected boundary based on the position of the last + IT candidate. */ + if (count & 1) + break; + seen_it = 0; + } + } + if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0) + { + /* This could be an IT instruction. */ + seen_it = insn; + it_count = count >> 1; + } + if ((insn & 0xf800) >= 0xe800) + count++; + else + count = (count + 2) | 1; + /* IT blocks contain at most 4 instructions. */ + if (count >= 8 && !seen_it) + return; + } + /* We found an IT instruction. */ + ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f); + if ((ifthen_state & 0xf) == 0) + ifthen_state = 0; +} + +/* NOTE: There are no checks in these routines that + the relevant number of data bytes exist. */ + +int +print_insn_arm (bfd_vma pc, struct disassemble_info *info) +{ + unsigned char b[4]; + long given; + int status; + int is_thumb = false; + int is_data = false; + unsigned int size = 4; + void (*printer) (bfd_vma, struct disassemble_info *, long); +#if 0 + bfd_boolean found = false; + + if (info->disassembler_options) + { + parse_disassembler_options (info->disassembler_options); + + /* To avoid repeated parsing of these options, we remove them here. */ + info->disassembler_options = NULL; + } + + /* First check the full symtab for a mapping symbol, even if there + are no usable non-mapping symbols for this address. */ + if (info->symtab != NULL + && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour) + { + bfd_vma addr; + int n; + int last_sym = -1; + enum map_type type = MAP_ARM; + + if (pc <= last_mapping_addr) + last_mapping_sym = -1; + is_thumb = (last_type == MAP_THUMB); + found = false; + /* Start scanning at the start of the function, or wherever + we finished last time. */ + n = info->symtab_pos + 1; + if (n < last_mapping_sym) + n = last_mapping_sym; + + /* Scan up to the location being disassembled. */ + for (; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + break; + if ((info->section == NULL + || info->section == info->symtab[n]->section) + && get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = true; + } + } + + if (!found) + { + n = info->symtab_pos; + if (n < last_mapping_sym - 1) + n = last_mapping_sym - 1; + + /* No mapping symbol found at this address. Look backwards + for a preceeding one. */ + for (; n >= 0; n--) + { + if (get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = true; + break; + } + } + } + + last_mapping_sym = last_sym; + last_type = type; + is_thumb = (last_type == MAP_THUMB); + is_data = (last_type == MAP_DATA); + + /* Look a little bit ahead to see if we should print out + two or four bytes of data. If there's a symbol, + mapping or otherwise, after two bytes then don't + print more. */ + if (is_data) + { + size = 4 - (pc & 3); + for (n = last_sym + 1; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + { + if (addr - pc < size) + size = addr - pc; + break; + } + } + /* If the next symbol is after three bytes, we need to + print only part of the data, so that we can use either + .byte or .short. */ + if (size == 3) + size = (pc & 1) ? 1 : 2; + } + } + + if (info->symbols != NULL) + { + if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) + { + coff_symbol_type * cs; + + cs = coffsymbol (*info->symbols); + is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT + || cs->native->u.syment.n_sclass == C_THUMBSTAT + || cs->native->u.syment.n_sclass == C_THUMBLABEL + || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC + || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC); + } + else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour + && !found) + { + /* If no mapping symbol has been found then fall back to the type + of the function symbol. */ + elf_symbol_type * es; + unsigned int type; + + es = *(elf_symbol_type **)(info->symbols); + type = ELF_ST_TYPE (es->internal_elf_sym.st_info); + + is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); + } + } +#else + int little; + + little = (info->endian == BFD_ENDIAN_LITTLE); + is_thumb |= (pc & 1); + pc &= ~(bfd_vma)1; +#endif + + if (force_thumb) + is_thumb = true; + + info->bytes_per_line = 4; + + if (is_data) + { + int i; + + /* size was already set above. */ + info->bytes_per_chunk = size; + printer = print_insn_data; + + status = info->read_memory_func (pc, (bfd_byte *)b, size, info); + given = 0; + if (little) + for (i = size - 1; i >= 0; i--) + given = b[i] | (given << 8); + else + for (i = 0; i < (int) size; i++) + given = b[i] | (given << 8); + } + else if (!is_thumb) + { + /* In ARM mode endianness is a straightforward issue: the instruction + is four bytes long and is either ordered 0123 or 3210. */ + printer = print_insn_arm_internal; + info->bytes_per_chunk = 4; + size = 4; + + status = info->read_memory_func (pc, (bfd_byte *)b, 4, info); + if (little) + given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + else + given = (b[3]) | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); + } + else + { + /* In Thumb mode we have the additional wrinkle of two + instruction lengths. Fortunately, the bits that determine + the length of the current instruction are always to be found + in the first two bytes. */ + printer = print_insn_thumb16; + info->bytes_per_chunk = 2; + size = 2; + + status = info->read_memory_func (pc, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8); + else + given = (b[1]) | (b[0] << 8); + + if (!status) + { + /* These bit patterns signal a four-byte Thumb + instruction. */ + if ((given & 0xF800) == 0xF800 + || (given & 0xF800) == 0xF000 + || (given & 0xF800) == 0xE800) + { + status = info->read_memory_func (pc + 2, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8) | (given << 16); + else + given = (b[1]) | (b[0] << 8) | (given << 16); + + printer = print_insn_thumb32; + size = 4; + } + } + + if (ifthen_address != pc) + find_ifthen_state(pc, info, little); + + if (ifthen_state) + { + if ((ifthen_state & 0xf) == 0x8) + ifthen_next_state = 0; + else + ifthen_next_state = (ifthen_state & 0xe0) + | ((ifthen_state & 0xf) << 1); + } + } + + if (status) + { + info->memory_error_func (status, pc, info); + return -1; + } + if (info->flags & INSN_HAS_RELOC) + /* If the instruction has a reloc associated with it, then + the offset field in the instruction will actually be the + addend for the reloc. (We are using REL type relocs). + In such cases, we can ignore the pc when computing + addresses, since the addend is not currently pc-relative. */ + pc = 0; + + printer (pc, info, given); + + if (is_thumb) + { + ifthen_state = ifthen_next_state; + ifthen_address += size; + } + return size; +} diff --git a/qemu/qemu-git/.svn/text-base/arm.ld.svn-base b/qemu/qemu-git/.svn/text-base/arm.ld.svn-base new file mode 100644 index 0000000..12b3edb --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/arm.ld.svn-base @@ -0,0 +1,153 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.gen_code) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .data1 : { *(.data1) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/.svn/text-base/bswap.h.svn-base b/qemu/qemu-git/.svn/text-base/bswap.h.svn-base new file mode 100644 index 0000000..4558704 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/bswap.h.svn-base @@ -0,0 +1,217 @@ +#ifndef BSWAP_H +#define BSWAP_H + +#include "config-host.h" + +#include + +#ifdef CONFIG_MACHINE_BSWAP_H +#include +#include +#include +#else + +#ifdef CONFIG_BYTESWAP_H +#include +#else + +#define bswap_16(x) \ +({ \ + uint16_t __x = (x); \ + ((uint16_t)( \ + (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ +}) + +#define bswap_32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +#define bswap_64(x) \ +({ \ + uint64_t __x = (x); \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ +}) + +#endif /* !CONFIG_BYTESWAP_H */ + +static inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +#endif /* ! CONFIG_MACHINE_BSWAP_H */ + +static inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(HOST_WORDS_BIGENDIAN) +#define be_bswap(v, size) (v) +#define le_bswap(v, size) bswap ## size(v) +#define be_bswaps(v, size) +#define le_bswaps(p, size) *p = bswap ## size(*p); +#else +#define le_bswap(v, size) (v) +#define be_bswap(v, size) bswap ## size(v) +#define le_bswaps(v, size) +#define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(_ARCH_PPC) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) +#define be32_to_cpupu(p) be32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v & 0xff; + p1[1] = v >> 8; +} + +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v & 0xff; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static inline uint32_t be32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24); +} + +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v & 0xff; +} + +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v & 0xff; +} + +#endif + +#ifdef HOST_WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/qemu/qemu-git/.svn/text-base/cache-utils.h.svn-base b/qemu/qemu-git/.svn/text-base/cache-utils.h.svn-base new file mode 100644 index 0000000..b45fde4 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cache-utils.h.svn-base @@ -0,0 +1,41 @@ +#ifndef QEMU_CACHE_UTILS_H +#define QEMU_CACHE_UTILS_H + +#if defined(_ARCH_PPC) +struct qemu_cache_conf { + unsigned long dcache_bsize; + unsigned long icache_bsize; +}; + +extern struct qemu_cache_conf qemu_cache_conf; + +extern void qemu_cache_utils_init(char **envp); + +/* mildly adjusted code from tcg-dyngen.c */ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p, start1, stop1; + unsigned long dsize = qemu_cache_conf.dcache_bsize; + unsigned long isize = qemu_cache_conf.icache_bsize; + + start1 = start & ~(dsize - 1); + stop1 = (stop + dsize - 1) & ~(dsize - 1); + for (p = start1; p < stop1; p += dsize) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + + start &= start & ~(isize - 1); + stop1 = (stop + isize - 1) & ~(isize - 1); + for (p = start1; p < stop1; p += isize) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} + +#else +#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) +#endif + +#endif /* QEMU_CACHE_UTILS_H */ diff --git a/qemu/qemu-git/.svn/text-base/config.h.svn-base b/qemu/qemu-git/.svn/text-base/config.h.svn-base new file mode 100644 index 0000000..e20f786 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/config.h.svn-base @@ -0,0 +1,2 @@ +#include "config-host.h" +#include "config-target.h" diff --git a/qemu/qemu-git/.svn/text-base/configure-small.svn-base b/qemu/qemu-git/.svn/text-base/configure-small.svn-base new file mode 100644 index 0000000..2f629e4 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/configure-small.svn-base @@ -0,0 +1,1094 @@ +#!/bin/sh +# +# qemu configure script (c) 2003 Fabrice Bellard +# +# set temporary file name +if test ! -z "$TMPDIR" ; then + TMPDIR1="${TMPDIR}" +elif test ! -z "$TEMPDIR" ; then + TMPDIR1="${TEMPDIR}" +else + TMPDIR1="/tmp" +fi + +TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" +TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o" +TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" + +trap "rm -f $TMPC $TMPO $TMPE ; exit" 0 2 3 15 + +compile_object() { + $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null +} + +compile_prog() { + local_cflags="$1" + local_ldflags="$2" + $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null +} + +# default parameters +cpu="" +static="no" +sparc_cpu="" +cross_prefix="" +cc="gcc" +block_drv_whitelist="" +host_cc="gcc" +ar="ar" +make="make" +ld="ld" +helper_cflags="" +libs_softmmu="" + +# parse CC options first +for opt do + optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` + case "$opt" in + --cross-prefix=*) cross_prefix="$optarg" + ;; + --cc=*) cc="$optarg" + ;; + --cpu=*) cpu="$optarg" + ;; + --extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS" + ;; + --extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS" + ;; + --sparc_cpu=*) + sparc_cpu="$optarg" + case $sparc_cpu in + v7|v8|v8plus|v8plusa) + cpu="sparc" + ;; + v9) + cpu="sparc64" + ;; + *) + echo "undefined SPARC architecture. Exiting"; + exit 1 + ;; + esac + ;; + esac +done +# OS specific +# Using uname is really, really broken. Once we have the right set of checks +# we can eliminate it's usage altogether + +cc="${cross_prefix}${cc}" +ar="${cross_prefix}${ar}" +ld="${cross_prefix}${ld}" + +# default flags for all hosts +QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" +CFLAGS="-g $CFLAGS" +QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" +QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" +QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" +QEMU_CFLAGS="-U_FORTIFY_SOURCE $QEMU_CFLAGS" +QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS" +LDFLAGS="-g $LDFLAGS" + +gcc_flags="-Wold-style-declaration -Wold-style-definition" +cat > $TMPC << EOF +int main(void) { } +EOF +for flag in $gcc_flags; do + if compile_prog "$QEMU_CFLAGS" "$flag" ; then + QEMU_CFLAGS="$flag $QEMU_CFLAGS" + fi +done + +# check that the C compiler works. +cat > $TMPC < $TMPC < /dev/null | /usr/bin/grep -v "no ar in"` + if test -z "$sol_ar" ; then + echo "Error: No path includes ar" + if test -f /usr/ccs/bin/ar ; then + echo "Add /usr/ccs/bin to your path and rerun configure" + fi + exit 1 + fi +fi + + +feature_not_found() { + feature=$1 + + echo "ERROR" + echo "ERROR: User requested feature $feature" + echo "ERROR: configure was not able to find it" + echo "ERROR" + exit 1; +} + +if test -z "$cross_prefix" ; then + +# --- +# big/little endian test +cat > $TMPC << EOF +#include +int main(int argc, char ** argv){ + volatile uint32_t i=0x01234567; + return (*((uint8_t*)(&i))) == 0x67; +} +EOF + +if compile_prog "" "" ; then +$TMPE && bigendian="yes" +else +echo big/little test failed +fi + +else + +# if cross compiling, cannot launch a program, so make a static guess +case "$cpu" in + armv4b|hppa|m68k|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + bigendian=yes + ;; +esac + +fi + +# host long bits test +hostlongbits="32" +case "$cpu" in + x86_64|alpha|ia64|sparc64|ppc64|s390x) + hostlongbits=64 + ;; +esac + + +########################################## +# zlib check + +cat > $TMPC << EOF +#include +int main(void) { zlibVersion(); return 0; } +EOF +if compile_prog "" "-lz" ; then + : +else + echo + echo "Error: zlib check failed" + echo "Make sure to have the zlib libs and headers installed." + echo + exit 1 +fi + +########################################## +# Sparse probe +if test "$sparse" != "no" ; then + if test -x "$(which cgcc 2>/dev/null)"; then + sparse=yes + else + if test "$sparse" = "yes" ; then + feature_not_found "sparse" + fi + sparse=no + fi +fi + +########################################## +# fnmatch() probe, used for ACL routines +fnmatch="no" +cat > $TMPC << EOF +#include +int main(void) +{ + fnmatch("foo", "foo", 0); + return 0; +} +EOF +if compile_prog "" "" ; then + fnmatch="yes" +fi + +########################################## +# pthread probe +PTHREADLIBS_LIST="-lpthread -lpthreadGC2" + +pthread=no +cat > $TMPC << EOF +#include +int main(void) { pthread_create(0,0,0,0); return 0; } +EOF +for pthread_lib in $PTHREADLIBS_LIST; do + if compile_prog "" "$pthread_lib" ; then + pthread=yes + LIBS="$pthread_lib $LIBS" + break + fi +done + +if test "$mingw32" != yes -a "$pthread" = no; then + echo + echo "Error: pthread check failed" + echo "Make sure to have the pthread libs and headers installed." + echo + exit 1 +fi + +########################################## +# iovec probe +cat > $TMPC < +#include +#include +int main(void) { struct iovec iov; return 0; } +EOF +iovec=no +if compile_prog "" "" ; then + iovec=yes +fi + +########################################## +# preadv probe +cat > $TMPC < +#include +#include +int main(void) { preadv; } +EOF +preadv=no +if compile_prog "" "" ; then + preadv=yes +fi + +# check if pipe2 is there +pipe2=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include +#include + +int main(void) +{ + int pipefd[2]; + pipe2(pipefd, O_CLOEXEC); + return 0; +} +EOF +if compile_prog "" "" ; then + pipe2=yes +fi + +# check if accept4 is there +accept4=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include +#include + +int main(void) +{ + accept4(0, NULL, NULL, SOCK_CLOEXEC); + return 0; +} +EOF +if compile_prog "" "" ; then + accept4=yes +fi + +# Search for bswap_32 function +byteswap_h=no +cat > $TMPC << EOF +#include +int main(void) { return bswap_32(0); } +EOF +if compile_prog "" "" ; then + byteswap_h=yes +fi + +# Search for bswap_32 function +bswap_h=no +cat > $TMPC << EOF +#include +#include +#include +int main(void) { return bswap32(0); } +EOF +if compile_prog "" "" ; then + bswap_h=yes +fi + +########################################## +# Do we need librt +cat > $TMPC < +#include +int main(void) { clockid_t id; return clock_gettime(id, NULL); } +EOF + +if compile_prog "" "" ; then + : +elif compile_prog "" "-lrt" ; then + LIBS="-lrt $LIBS" +fi + +if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ + "$aix" != "yes" ; then + libs_softmmu="-lutil $libs_softmmu" +fi + +########################################## +# check if the compiler defines offsetof + +need_offsetof=yes +cat > $TMPC << EOF +#include +int main(void) { struct s { int f; }; return offsetof(struct s, f); } +EOF +if compile_prog "" "" ; then + need_offsetof=no +fi + +########################################## +# check if the compiler understands attribute warn_unused_result +# +# This could be smarter, but gcc -Werror does not error out even when warning +# about attribute warn_unused_result + +gcc_attribute_warn_unused_result=no +cat > $TMPC << EOF +#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4) +#error gcc 3.3 or older +#endif +int main(void) { return 0;} +EOF +if compile_prog "" ""; then + gcc_attribute_warn_unused_result=yes +fi + +########################################## +# check if we have fdatasync + +fdatasync=no +cat > $TMPC << EOF +#include +int main(void) { return fdatasync(0); } +EOF +if compile_prog "" "" ; then + fdatasync=yes +fi + +# End of CC checks +# After here, no more $cc or $ld runs + +if test "$debug" = "no" ; then + CFLAGS="-O2 $CFLAGS" +fi + +# Consult white-list to determine whether to enable werror +# by default. Only enable by default for git builds +z_version=`cut -f3 -d. $source_path/VERSION` + +if test -z "$werror" ; then + if test "$z_version" = "50" -a \ + "$linux" = "yes" ; then + werror="yes" + else + werror="no" + fi +fi + +# Disable zero malloc errors for official releases unless explicitly told to +# enable/disable +if test -z "$zero_malloc" ; then + if test "$z_version" = "50" ; then + zero_malloc="no" + else + zero_malloc="yes" + fi +fi + +if test "$werror" = "yes" ; then + QEMU_CFLAGS="-Werror $QEMU_CFLAGS" +fi + +if test "$solaris" = "no" ; then + if $ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then + LDFLAGS="-Wl,--warn-common $LDFLAGS" + fi +fi + +echo "Source path $source_path" +echo "C compiler $cc" +echo "Host C compiler $host_cc" +echo "CFLAGS $CFLAGS" +echo "QEMU_CFLAGS $QEMU_CFLAGS" +echo "LDFLAGS $LDFLAGS" +echo "make $make" +echo "host CPU $cpu" +echo "host big endian $bigendian" +echo "target list arm-softmmu" +echo "tcg debug enabled $debug_tcg" +echo "gprof enabled $gprof" +echo "sparse enabled $sparse" +echo "strip binaries $strip_opt" +echo "profiler $profiler" +echo "static build $static" +echo "-Werror enabled $werror" +echo "mingw32 support $mingw32" +echo "Block whitelist $block_drv_whitelist" +if test -n "$sparc_cpu"; then + echo "Target Sparc Arch $sparc_cpu" +fi +echo "preadv support $preadv" +echo "fdatasync $fdatasync" + +config_host_mak="config-host.mak" +config_host_ld="config-host.ld" + +echo "# Automatically generated by configure - do not modify" > $config_host_mak +printf "# Configured with:" >> $config_host_mak +printf " '%s'" "$0" "$@" >> $config_host_mak +echo >> $config_host_mak + +case "$cpu" in + i386|x86_64|alpha|cris|hppa|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + ARCH=$cpu + ;; + armv4b|armv4l) + ARCH=arm + ;; + *) + echo "Unsupported CPU = $cpu" + exit 1 + ;; +esac +echo "ARCH=$ARCH" >> $config_host_mak +if test "$debug_tcg" = "yes" ; then + echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak +fi +if test "$debug" = "yes" ; then + echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak +fi +if test "$strip_opt" = "yes" ; then + echo "STRIP_OPT=-s" >> $config_host_mak +fi +if test "$bigendian" = "yes" ; then + echo "HOST_WORDS_BIGENDIAN=y" >> $config_host_mak +fi +echo "HOST_LONG_BITS=$hostlongbits" >> $config_host_mak +if test "$mingw32" = "yes" ; then + echo "CONFIG_WIN32=y" >> $config_host_mak +else + echo "CONFIG_POSIX=y" >> $config_host_mak +fi + +if test "$linux" = "yes" ; then + echo "CONFIG_LINUX=y" >> $config_host_mak +fi + +if test "$darwin" = "yes" ; then + echo "CONFIG_DARWIN=y" >> $config_host_mak +fi + +if test "$aix" = "yes" ; then + echo "CONFIG_AIX=y" >> $config_host_mak +fi + +if test "$solaris" = "yes" ; then + echo "CONFIG_SOLARIS=y" >> $config_host_mak + echo "CONFIG_SOLARIS_VERSION=$solarisrev" >> $config_host_mak + if test "$needs_libsunmath" = "yes" ; then + echo "CONFIG_NEEDS_LIBSUNMATH=y" >> $config_host_mak + fi +fi +if test "$static" = "yes" ; then + echo "CONFIG_STATIC=y" >> $config_host_mak + LDFLAGS="-static $LDFLAGS" +fi +if test $profiler = "yes" ; then + echo "CONFIG_PROFILER=y" >> $config_host_mak +fi +echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak +if test "$fnmatch" = "yes" ; then + echo "CONFIG_FNMATCH=y" >> $config_host_mak +fi +qemu_version=`head $source_path/VERSION` +echo "VERSION=$qemu_version" >>$config_host_mak +echo "PKGVERSION=$pkgversion" >>$config_host_mak +echo "SRC_PATH=$source_path" >> $config_host_mak +if test "$pipe2" = "yes" ; then + echo "CONFIG_PIPE2=y" >> $config_host_mak +fi +if test "$accept4" = "yes" ; then + echo "CONFIG_ACCEPT4=y" >> $config_host_mak +fi +if test "$byteswap_h" = "yes" ; then + echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak +fi +if test "$bswap_h" = "yes" ; then + echo "CONFIG_MACHINE_BSWAP_H=y" >> $config_host_mak +fi +if test "$iovec" = "yes" ; then + echo "CONFIG_IOVEC=y" >> $config_host_mak +fi +if test "$preadv" = "yes" ; then + echo "CONFIG_PREADV=y" >> $config_host_mak +fi +if test "$need_offsetof" = "yes" ; then + echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak +fi +if test "$gcc_attribute_warn_unused_result" = "yes" ; then + echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak +fi +if test "$fdatasync" = "yes" ; then + echo "CONFIG_FDATASYNC=y" >> $config_host_mak +fi + +# XXX: suppress that +if [ "$bsd" = "yes" ] ; then + echo "CONFIG_BSD=y" >> $config_host_mak +fi + +if test "$zero_malloc" = "yes" ; then + echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak +fi + +echo "MAKE=$make" >> $config_host_mak +echo "CC=$cc" >> $config_host_mak +echo "HOST_CC=$host_cc" >> $config_host_mak +if test "$sparse" = "yes" ; then + echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak + echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak + echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak +fi +echo "AR=$ar" >> $config_host_mak +echo "LD=$ld" >> $config_host_mak +echo "CFLAGS=$CFLAGS" >> $config_host_mak +echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak +echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak +echo "LDFLAGS=$LDFLAGS" >> $config_host_mak +echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak +echo "ARLIBS_END=$arlibs_end" >> $config_host_mak +echo "LIBS+=$LIBS" >> $config_host_mak +echo "EXESUF=$EXESUF" >> $config_host_mak + +# generate list of library paths for linker script + +$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > ${config_host_ld} + +if test -f ${config_host_ld}~ ; then + if cmp -s $config_host_ld ${config_host_ld}~ ; then + mv ${config_host_ld}~ $config_host_ld + else + rm ${config_host_ld}~ + fi +fi + +config_target_mak=arm-softmmu/config-target.mak + +mkdir -p arm-softmmu +mkdir -p arm-softmmu/fpu +mkdir -p arm-softmmu/tcg + +# +# don't use ln -sf as not all "ln -sf" over write the file/link +# +rm -f arm-softmmu/Makefile +ln -s $source_path/Makefile-small.target arm-softmmu/Makefile + + +echo "# Automatically generated by configure - do not modify" > $config_target_mak + +gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" +target_phys_bits=32 +echo "TARGET_ARCH=arm" >> $config_target_mak +echo "TARGET_ARM=y" >> $config_target_mak +echo "TARGET_BASE_ARCH=arm" >> $config_target_mak +if [ $target_phys_bits -lt $hostlongbits ] ; then + target_phys_bits=$hostlongbits +fi +echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak +echo "CONFIG_SOFTMMU=y" >> $config_target_mak +echo "LIBS+=$libs_softmmu" >> $config_target_mak +echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak +echo "subdir-arm-softmmu: subdir-libhw$target_phys_bits" >> $config_host_mak +list="" +if test ! -z "$gdb_xml_files" ; then + for x in $gdb_xml_files; do + list="$list $source_path/gdb-xml/$x" + done + echo "TARGET_XML_FILES=$list" >> $config_target_mak +fi + +echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak +#echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak + +# generate QEMU_CFLAGS/LDFLAGS for targets + +cflags="" +ldflags="" + +if test "$ARCH" = "sparc64" ; then + cflags="-I\$(SRC_PATH)/tcg/sparc $cflags" +elif test "$ARCH" = "s390x" ; then + cflags="-I\$(SRC_PATH)/tcg/s390 $cflags" +else + cflags="-I\$(SRC_PATH)/tcg/\$(ARCH) $cflags" +fi +cflags="-I\$(SRC_PATH)/tcg $cflags" +cflags="-I\$(SRC_PATH)/fpu $cflags" + +for i in $ARCH arm ; do + case "$i" in + alpha) + echo "CONFIG_ALPHA_DIS=y" >> $config_target_mak + ;; + arm) + echo "CONFIG_ARM_DIS=y" >> $config_target_mak + ;; + cris) + echo "CONFIG_CRIS_DIS=y" >> $config_target_mak + ;; + hppa) + echo "CONFIG_HPPA_DIS=y" >> $config_target_mak + ;; + i386|x86_64) + echo "CONFIG_I386_DIS=y" >> $config_target_mak + ;; + m68k) + echo "CONFIG_M68K_DIS=y" >> $config_target_mak + ;; + microblaze) + echo "CONFIG_MICROBLAZE_DIS=y" >> $config_target_mak + ;; + mips*) + echo "CONFIG_MIPS_DIS=y" >> $config_target_mak + ;; + ppc*) + echo "CONFIG_PPC_DIS=y" >> $config_target_mak + ;; + s390*) + echo "CONFIG_S390_DIS=y" >> $config_target_mak + ;; + sh4) + echo "CONFIG_SH4_DIS=y" >> $config_target_mak + ;; + sparc*) + echo "CONFIG_SPARC_DIS=y" >> $config_target_mak + ;; + esac +done + +case "$ARCH" in +alpha) + # Ensure there's only a single GP + cflags="-msmall-data $cflags" +;; +ia64) + cflags="-mno-sdata $cflags" +;; +esac + +if test "$gprof" = "yes" ; then + echo "TARGET_GPROF=yes" >> $config_target_mak + ldflags="-p $ldflags" + echo "GPROF_CFLAGS=-p" >> $config_target_mak +fi + +linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/\$(ARCH).ld" +case "$ARCH" in +ia64) + ldflags="-Wl,-G0 $linker_script -static $ldflags" + ;; +esac + +echo "LDFLAGS+=$ldflags" >> $config_target_mak +echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak + +# build tree in object directory if source path is different from current one +if test "$source_path_used" = "yes" ; then + FILES="Makefile-small" + # remove the link and recreate it, as not all "ln -sf" overwrite the link + for f in $FILES ; do + rm -f $f + ln -s $source_path/$f $f + done +fi + +for hwlib in 32 64; do + d=libhw$hwlib + mkdir -p $d + rm -f $d/Makefile + ln -s $source_path/Makefile-small.hw $d/Makefile + echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" >> $d/config.mak +done diff --git a/qemu/qemu-git/.svn/text-base/cpu-all.h.svn-base b/qemu/qemu-git/.svn/text-base/cpu-all.h.svn-base new file mode 100644 index 0000000..57b69f8 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cpu-all.h.svn-base @@ -0,0 +1,1076 @@ +/* + * defines common to all virtual CPUs + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_ALL_H +#define CPU_ALL_H + +#include "qemu-common.h" +#include "cpu-common.h" + +/* some important defines: + * + * WORDS_ALIGNED : if defined, the host cpu can only make word aligned + * memory accesses. + * + * HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and + * otherwise little endian. + * + * (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet)) + * + * TARGET_WORDS_BIGENDIAN : same for target cpu + */ + +#include "softfloat.h" + +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#define BSWAP_NEEDED +#endif + +#ifdef BSWAP_NEEDED + +static inline uint16_t tswap16(uint16_t s) +{ + return bswap16(s); +} + +static inline uint32_t tswap32(uint32_t s) +{ + return bswap32(s); +} + +static inline uint64_t tswap64(uint64_t s) +{ + return bswap64(s); +} + +static inline void tswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void tswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void tswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#else + +static inline uint16_t tswap16(uint16_t s) +{ + return s; +} + +static inline uint32_t tswap32(uint32_t s) +{ + return s; +} + +static inline uint64_t tswap64(uint64_t s) +{ + return s; +} + +static inline void tswap16s(uint16_t *s) +{ +} + +static inline void tswap32s(uint32_t *s) +{ +} + +static inline void tswap64s(uint64_t *s) +{ +} + +#endif + +#if TARGET_LONG_SIZE == 4 +#define tswapl(s) tswap32(s) +#define tswapls(s) tswap32s((uint32_t *)(s)) +#define bswaptls(s) bswap32s(s) +#else +#define tswapl(s) tswap64(s) +#define tswapls(s) tswap64s((uint64_t *)(s)) +#define bswaptls(s) bswap64s(s) +#endif + +typedef union { + float32 f; + uint32_t l; +} CPU_FloatU; + +/* NOTE: arm FPA is horrible as double 32 bit words are stored in big + endian ! */ +typedef union { + float64 d; +#if defined(HOST_WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upper; + uint32_t lower; + } l; +#else + struct { + uint32_t lower; + uint32_t upper; + } l; +#endif + uint64_t ll; +} CPU_DoubleU; + +#ifdef TARGET_SPARC +typedef union { + float128 q; +#if defined(HOST_WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; +#endif + +/* CPU memory access without any memory or io remapping */ + +/* + * the generic syntax for the memory accesses is: + * + * load: ld{type}{sign}{size}{endian}_{access_type}(ptr) + * + * store: st{type}{size}{endian}_{access_type}(ptr, val) + * + * type is: + * (empty): integer access + * f : float access + * + * sign is: + * (empty): for floats or 32 bit size + * u : unsigned + * s : signed + * + * size is: + * b: 8 bits + * w: 16 bits + * l: 32 bits + * q: 64 bits + * + * endian is: + * (empty): target cpu endianness or 8 bit access + * r : reversed target cpu endianness (not implemented yet) + * be : big endian (not implemented yet) + * le : little endian (not implemented yet) + * + * access_type is: + * raw : host memory access + * user : user mode access using soft MMU + * kernel : kernel mode access using soft MMU + */ +static inline int ldub_p(const void *ptr) +{ + return *(uint8_t *)ptr; +} + +static inline int ldsb_p(const void *ptr) +{ + return *(int8_t *)ptr; +} + +static inline void stb_p(void *ptr, int v) +{ + *(uint8_t *)ptr = v; +} + +/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the + kernel handles unaligned load/stores may give better results, but + it is a system wide setting : bad */ +#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) + +/* conservative code for little endian unaligned accesses */ +static inline int lduw_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + const uint8_t *p = ptr; + return p[0] | (p[1] << 8); +#endif +} + +static inline int ldsw_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; +#else + const uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline int ldl_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + const uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +#endif +} + +static inline uint64_t ldq_le_p(const void *ptr) +{ + const uint8_t *p = ptr; + uint32_t v1, v2; + v1 = ldl_le_p(p); + v2 = ldl_le_p(p + 4); + return v1 | ((uint64_t)v2 << 32); +} + +static inline void stw_le_p(void *ptr, int v) +{ +#ifdef _ARCH_PPC + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; +#endif +} + +static inline void stl_le_p(void *ptr, int v) +{ +#ifdef _ARCH_PPC + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +#endif +} + +static inline void stq_le_p(void *ptr, uint64_t v) +{ + uint8_t *p = ptr; + stl_le_p(p, (uint32_t)v); + stl_le_p(p + 4, v >> 32); +} + +/* float access */ + +static inline float32 ldfl_le_p(const void *ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = ldl_le_p(ptr); + return u.f; +} + +static inline void stfl_le_p(void *ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + stl_le_p(ptr, u.i); +} + +static inline float64 ldfq_le_p(const void *ptr) +{ + CPU_DoubleU u; + u.l.lower = ldl_le_p(ptr); + u.l.upper = ldl_le_p(ptr + 4); + return u.d; +} + +static inline void stfq_le_p(void *ptr, float64 v) +{ + CPU_DoubleU u; + u.d = v; + stl_le_p(ptr, u.l.lower); + stl_le_p(ptr + 4, u.l.upper); +} + +#else + +static inline int lduw_le_p(const void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw_le_p(const void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl_le_p(const void *ptr) +{ + return *(uint32_t *)ptr; +} + +static inline uint64_t ldq_le_p(const void *ptr) +{ + return *(uint64_t *)ptr; +} + +static inline void stw_le_p(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl_le_p(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +static inline void stq_le_p(void *ptr, uint64_t v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float32 ldfl_le_p(const void *ptr) +{ + return *(float32 *)ptr; +} + +static inline float64 ldfq_le_p(const void *ptr) +{ + return *(float64 *)ptr; +} + +static inline void stfl_le_p(void *ptr, float32 v) +{ + *(float32 *)ptr = v; +} + +static inline void stfq_le_p(void *ptr, float64 v) +{ + *(float64 *)ptr = v; +} +#endif + +#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) + +static inline int lduw_be_p(const void *ptr) +{ +#if defined(__i386__) + int val; + asm volatile ("movzwl %1, %0\n" + "xchgb %b0, %h0\n" + : "=q" (val) + : "m" (*(uint16_t *)ptr)); + return val; +#else + const uint8_t *b = ptr; + return ((b[0] << 8) | b[1]); +#endif +} + +static inline int ldsw_be_p(const void *ptr) +{ +#if defined(__i386__) + int val; + asm volatile ("movzwl %1, %0\n" + "xchgb %b0, %h0\n" + : "=q" (val) + : "m" (*(uint16_t *)ptr)); + return (int16_t)val; +#else + const uint8_t *b = ptr; + return (int16_t)((b[0] << 8) | b[1]); +#endif +} + +static inline int ldl_be_p(const void *ptr) +{ +#if defined(__i386__) || defined(__x86_64__) + int val; + asm volatile ("movl %1, %0\n" + "bswap %0\n" + : "=r" (val) + : "m" (*(uint32_t *)ptr)); + return val; +#else + const uint8_t *b = ptr; + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +#endif +} + +static inline uint64_t ldq_be_p(const void *ptr) +{ + uint32_t a,b; + a = ldl_be_p(ptr); + b = ldl_be_p((uint8_t *)ptr + 4); + return (((uint64_t)a<<32)|b); +} + +static inline void stw_be_p(void *ptr, int v) +{ +#if defined(__i386__) + asm volatile ("xchgb %b0, %h0\n" + "movw %w0, %1\n" + : "=q" (v) + : "m" (*(uint16_t *)ptr), "0" (v)); +#else + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 8; + d[1] = v; +#endif +} + +static inline void stl_be_p(void *ptr, int v) +{ +#if defined(__i386__) || defined(__x86_64__) + asm volatile ("bswap %0\n" + "movl %0, %1\n" + : "=r" (v) + : "m" (*(uint32_t *)ptr), "0" (v)); +#else + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +#endif +} + +static inline void stq_be_p(void *ptr, uint64_t v) +{ + stl_be_p(ptr, v >> 32); + stl_be_p((uint8_t *)ptr + 4, v); +} + +/* float access */ + +static inline float32 ldfl_be_p(const void *ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = ldl_be_p(ptr); + return u.f; +} + +static inline void stfl_be_p(void *ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + stl_be_p(ptr, u.i); +} + +static inline float64 ldfq_be_p(const void *ptr) +{ + CPU_DoubleU u; + u.l.upper = ldl_be_p(ptr); + u.l.lower = ldl_be_p((uint8_t *)ptr + 4); + return u.d; +} + +static inline void stfq_be_p(void *ptr, float64 v) +{ + CPU_DoubleU u; + u.d = v; + stl_be_p(ptr, u.l.upper); + stl_be_p((uint8_t *)ptr + 4, u.l.lower); +} + +#else + +static inline int lduw_be_p(const void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw_be_p(const void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl_be_p(const void *ptr) +{ + return *(uint32_t *)ptr; +} + +static inline uint64_t ldq_be_p(const void *ptr) +{ + return *(uint64_t *)ptr; +} + +static inline void stw_be_p(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl_be_p(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +static inline void stq_be_p(void *ptr, uint64_t v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float32 ldfl_be_p(const void *ptr) +{ + return *(float32 *)ptr; +} + +static inline float64 ldfq_be_p(const void *ptr) +{ + return *(float64 *)ptr; +} + +static inline void stfl_be_p(void *ptr, float32 v) +{ + *(float32 *)ptr = v; +} + +static inline void stfq_be_p(void *ptr, float64 v) +{ + *(float64 *)ptr = v; +} + +#endif + +/* target CPU memory access functions */ +#if defined(TARGET_WORDS_BIGENDIAN) +#define lduw_p(p) lduw_be_p(p) +#define ldsw_p(p) ldsw_be_p(p) +#define ldl_p(p) ldl_be_p(p) +#define ldq_p(p) ldq_be_p(p) +#define ldfl_p(p) ldfl_be_p(p) +#define ldfq_p(p) ldfq_be_p(p) +#define stw_p(p, v) stw_be_p(p, v) +#define stl_p(p, v) stl_be_p(p, v) +#define stq_p(p, v) stq_be_p(p, v) +#define stfl_p(p, v) stfl_be_p(p, v) +#define stfq_p(p, v) stfq_be_p(p, v) +#else +#define lduw_p(p) lduw_le_p(p) +#define ldsw_p(p) ldsw_le_p(p) +#define ldl_p(p) ldl_le_p(p) +#define ldq_p(p) ldq_le_p(p) +#define ldfl_p(p) ldfl_le_p(p) +#define ldfq_p(p) ldfq_le_p(p) +#define stw_p(p, v) stw_le_p(p, v) +#define stl_p(p, v) stl_le_p(p, v) +#define stq_p(p, v) stq_le_p(p, v) +#define stfl_p(p, v) stfl_le_p(p, v) +#define stfq_p(p, v) stfq_le_p(p, v) +#endif + +/* MMU memory access macros */ + +#if defined(CONFIG_USER_ONLY) +#include +#include "qemu-types.h" + +/* On some host systems the guest address space is reserved on the host. + * This allows the guest address space to be offset to a convenient location. + */ +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long guest_base; +extern int have_guest_base; +#define GUEST_BASE guest_base +#else +#define GUEST_BASE 0ul +#endif + +/* All direct uses of g2h and h2g need to go away for usermode softmmu. */ +#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) +#define h2g(x) ({ \ + unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \ + /* Check if given address fits target address space */ \ + assert(__ret == (abi_ulong)__ret); \ + (abi_ulong)__ret; \ +}) +#define h2g_valid(x) ({ \ + unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \ + (__guest == (abi_ulong)__guest); \ +}) + +#define saddr(x) g2h(x) +#define laddr(x) g2h(x) + +#else /* !CONFIG_USER_ONLY */ +/* NOTE: we use double casts if pointers and target_ulong have + different sizes */ +#define saddr(x) (uint8_t *)(long)(x) +#define laddr(x) (uint8_t *)(long)(x) +#endif + +#define ldub_raw(p) ldub_p(laddr((p))) +#define ldsb_raw(p) ldsb_p(laddr((p))) +#define lduw_raw(p) lduw_p(laddr((p))) +#define ldsw_raw(p) ldsw_p(laddr((p))) +#define ldl_raw(p) ldl_p(laddr((p))) +#define ldq_raw(p) ldq_p(laddr((p))) +#define ldfl_raw(p) ldfl_p(laddr((p))) +#define ldfq_raw(p) ldfq_p(laddr((p))) +#define stb_raw(p, v) stb_p(saddr((p)), v) +#define stw_raw(p, v) stw_p(saddr((p)), v) +#define stl_raw(p, v) stl_p(saddr((p)), v) +#define stq_raw(p, v) stq_p(saddr((p)), v) +#define stfl_raw(p, v) stfl_p(saddr((p)), v) +#define stfq_raw(p, v) stfq_p(saddr((p)), v) + + +#if defined(CONFIG_USER_ONLY) + +/* if user mode, no other memory access functions */ +#define ldub(p) ldub_raw(p) +#define ldsb(p) ldsb_raw(p) +#define lduw(p) lduw_raw(p) +#define ldsw(p) ldsw_raw(p) +#define ldl(p) ldl_raw(p) +#define ldq(p) ldq_raw(p) +#define ldfl(p) ldfl_raw(p) +#define ldfq(p) ldfq_raw(p) +#define stb(p, v) stb_raw(p, v) +#define stw(p, v) stw_raw(p, v) +#define stl(p, v) stl_raw(p, v) +#define stq(p, v) stq_raw(p, v) +#define stfl(p, v) stfl_raw(p, v) +#define stfq(p, v) stfq_raw(p, v) + +#define ldub_code(p) ldub_raw(p) +#define ldsb_code(p) ldsb_raw(p) +#define lduw_code(p) lduw_raw(p) +#define ldsw_code(p) ldsw_raw(p) +#define ldl_code(p) ldl_raw(p) +#define ldq_code(p) ldq_raw(p) + +#define ldub_kernel(p) ldub_raw(p) +#define ldsb_kernel(p) ldsb_raw(p) +#define lduw_kernel(p) lduw_raw(p) +#define ldsw_kernel(p) ldsw_raw(p) +#define ldl_kernel(p) ldl_raw(p) +#define ldq_kernel(p) ldq_raw(p) +#define ldfl_kernel(p) ldfl_raw(p) +#define ldfq_kernel(p) ldfq_raw(p) +#define stb_kernel(p, v) stb_raw(p, v) +#define stw_kernel(p, v) stw_raw(p, v) +#define stl_kernel(p, v) stl_raw(p, v) +#define stq_kernel(p, v) stq_raw(p, v) +#define stfl_kernel(p, v) stfl_raw(p, v) +#define stfq_kernel(p, vt) stfq_raw(p, v) + +#endif /* defined(CONFIG_USER_ONLY) */ + +/* page related stuff */ + +#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) +#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) +#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) + +/* ??? These should be the larger of unsigned long and target_ulong. */ +extern unsigned long qemu_real_host_page_size; +extern unsigned long qemu_host_page_bits; +extern unsigned long qemu_host_page_size; +extern unsigned long qemu_host_page_mask; + +#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask) + +/* same as PROT_xxx */ +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 +/* original state of the write flag (used when tracking self-modifying + code */ +#define PAGE_WRITE_ORG 0x0010 +#define PAGE_RESERVED 0x0020 + +void page_dump(FILE *f); +int walk_memory_regions(void *, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)); +int page_get_flags(target_ulong address); +void page_set_flags(target_ulong start, target_ulong end, int flags); +int page_check_range(target_ulong start, target_ulong len, int flags); + +void cpu_exec_init_all(unsigned long tb_size); +CPUState *cpu_copy(CPUState *env); +CPUState *qemu_get_cpu(int cpu); + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); +void cpu_dump_statistics (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); + +void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern CPUState *first_cpu; +extern CPUState *cpu_single_env; +extern int64_t qemu_icount; +extern int use_icount; + +#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ +#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ +#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ +#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ +#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ +#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ +#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ +#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ +#define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ +#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ +#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */ + +void cpu_interrupt(CPUState *s, int mask); +void cpu_reset_interrupt(CPUState *env, int mask); + +void cpu_exit(CPUState *s); + +int qemu_cpu_has_work(CPUState *env); + +/* Breakpoint/watchpoint flags */ +#define BP_MEM_READ 0x01 +#define BP_MEM_WRITE 0x02 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) +#define BP_STOP_BEFORE_ACCESS 0x04 +#define BP_WATCHPOINT_HIT 0x08 +#define BP_GDB 0x10 +#define BP_CPU 0x20 + +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint); +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags); +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint); +void cpu_breakpoint_remove_all(CPUState *env, int mask); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint); +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, + target_ulong len, int flags); +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint); +void cpu_watchpoint_remove_all(CPUState *env, int mask); + +#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */ +#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */ +#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */ + +void cpu_single_step(CPUState *env, int enabled); +void cpu_reset(CPUState *s); + +/* Return the physical page corresponding to a virtual one. Use it + only for debugging because no protection checks are done. Return -1 + if no page found. */ +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); + +#define CPU_LOG_TB_OUT_ASM (1 << 0) +#define CPU_LOG_TB_IN_ASM (1 << 1) +#define CPU_LOG_TB_OP (1 << 2) +#define CPU_LOG_TB_OP_OPT (1 << 3) +#define CPU_LOG_INT (1 << 4) +#define CPU_LOG_EXEC (1 << 5) +#define CPU_LOG_PCALL (1 << 6) +#define CPU_LOG_IOPORT (1 << 7) +#define CPU_LOG_TB_CPU (1 << 8) +#define CPU_LOG_RESET (1 << 9) + +/* define log items */ +typedef struct CPULogItem { + int mask; + const char *name; + const char *help; +} CPULogItem; + +extern const CPULogItem cpu_log_items[]; + +void cpu_set_log(int log_flags); +void cpu_set_log_filename(const char *filename); +int cpu_str_to_log_mask(const char *str); + +/* IO ports API */ +#include "ioport.h" + +/* memory API */ + +extern int phys_ram_fd; +extern uint8_t *phys_ram_dirty; +extern ram_addr_t ram_size; +extern ram_addr_t last_ram_offset; + +/* physical memory access */ + +/* MMIO pages are identified by a combination of an IO device index and + 3 flags. The ROMD code stores the page ram offset in iotlb entry, + so only a limited number of ids are avaiable. */ + +#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) + +/* Flags stored in the low bits of the TLB virtual address. These are + defined so that fast path ram access is all zeros. */ +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << 3) +/* Set if TLB entry references a clean RAM page. The iotlb entry will + contain the page physical address. */ +#define TLB_NOTDIRTY (1 << 4) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << 5) + +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); + +#define VGA_DIRTY_FLAG 0x01 +#define CODE_DIRTY_FLAG 0x02 +#define MIGRATION_DIRTY_FLAG 0x08 + +/* read dirty bit (return 0 or 1) */ +static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; +} + +static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, + int dirty_flags) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; +} + +static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) +{ + phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; +} + +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags); +void cpu_tlb_update_dirty(CPUState *env); + +int cpu_physical_memory_set_dirty_tracking(int enable); + +int cpu_physical_memory_get_dirty_tracking(void); + +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +/* Coalesced MMIO regions are areas where write operations can be reordered. + * This usually implies that write operations are side-effect free. This allows + * batching which can make a major impact on performance when using + * virtualization. + */ +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); + +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); + +/*******************************************/ +/* host CPU ticks (if available) */ + +#if defined(_ARCH_PPC) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t retval; +#ifdef _ARCH_PPC64 + /* This reads timebase in one 64bit go and includes Cell workaround from: + http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html + */ + __asm__ __volatile__ ( + "mftb %0\n\t" + "cmpwi %0,0\n\t" + "beq- $-8" + : "=r" (retval)); +#else + /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */ + unsigned long junk; + __asm__ __volatile__ ( + "mftbu %1\n\t" + "mftb %L0\n\t" + "mftbu %0\n\t" + "cmpw %0,%1\n\t" + "bne $-16" + : "=r" (retval), "=r" (junk)); +#endif + return retval; +} + +#elif defined(__i386__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} + +#elif defined(__x86_64__) + +static inline int64_t cpu_get_real_ticks(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} + +#elif defined(__hppa__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int val; + asm volatile ("mfctl %%cr16, %0" : "=r"(val)); + return val; +} + +#elif defined(__ia64) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); + return val; +} + +#elif defined(__s390__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); + return val; +} + +#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + +static inline int64_t cpu_get_real_ticks (void) +{ +#if defined(_LP64) + uint64_t rval; + asm volatile("rd %%tick,%0" : "=r"(rval)); + return rval; +#else + union { + uint64_t i64; + struct { + uint32_t high; + uint32_t low; + } i32; + } rval; + asm volatile("rd %%tick,%1; srlx %1,32,%0" + : "=r"(rval.i32.high), "=r"(rval.i32.low)); + return rval.i64; +#endif +} + +#elif defined(__mips__) && \ + ((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)) +/* + * binutils wants to use rdhwr only on mips32r2 + * but as linux kernel emulate it, it's fine + * to use it. + * + */ +#define MIPS_RDHWR(rd, value) { \ + __asm__ __volatile__ ( \ + ".set push\n\t" \ + ".set mips32r2\n\t" \ + "rdhwr %0, "rd"\n\t" \ + ".set pop" \ + : "=r" (value)); \ +} + +static inline int64_t cpu_get_real_ticks(void) +{ +/* On kernels >= 2.6.25 rdhwr , $2 and $3 are emulated */ + uint32_t count; + static uint32_t cyc_per_count = 0; + + if (!cyc_per_count) + MIPS_RDHWR("$3", cyc_per_count); + + MIPS_RDHWR("$2", count); + return (int64_t)(count * cyc_per_count); +} + +#else +/* The host CPU doesn't have an easily accessible cycle counter. + Just return a monotonically increasing value. This will be + totally wrong, but hopefully better than nothing. */ +static inline int64_t cpu_get_real_ticks (void) +{ + static int64_t ticks = 0; + return ticks++; +} +#endif + +/* profiling */ +#ifdef CONFIG_PROFILER +static inline int64_t profile_getclock(void) +{ + return cpu_get_real_ticks(); +} + +extern int64_t qemu_time, qemu_time_start; +extern int64_t tlb_flush_time; +extern int64_t dev_time; +#endif + +void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, + uint64_t mcg_status, uint64_t addr, uint64_t misc); + +#endif /* CPU_ALL_H */ diff --git a/qemu/qemu-git/.svn/text-base/cpu-common.h.svn-base b/qemu/qemu-git/.svn/text-base/cpu-common.h.svn-base new file mode 100644 index 0000000..6302372 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cpu-common.h.svn-base @@ -0,0 +1,90 @@ +#ifndef CPU_COMMON_H +#define CPU_COMMON_H 1 + +/* CPU interfaces that are target indpendent. */ + +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) +#define WORDS_ALIGNED +#endif + +#include "bswap.h" + +/* address in the RAM (different from a physical address) */ +typedef unsigned long ram_addr_t; + +/* memory API */ + +typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); + +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset, + ram_addr_t region_offset); +static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0); +} + +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr); +ram_addr_t qemu_ram_alloc(ram_addr_t); +void qemu_ram_free(ram_addr_t addr); +/* This should only be used for ram local to a device. */ +void *qemu_get_ram_ptr(ram_addr_t addr); +/* This should not be used by devices. */ +ram_addr_t qemu_ram_addr_from_host(void *ptr); + +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque); +void cpu_unregister_io_memory(int table_address); + +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write); +static inline void cpu_physical_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, buf, len, 0); +} +static inline void cpu_physical_memory_write(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); +} +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write); +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len); +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); +void cpu_unregister_map_client(void *cookie); + +uint32_t ldub_phys(target_phys_addr_t addr); +uint32_t lduw_phys(target_phys_addr_t addr); +uint32_t ldl_phys(target_phys_addr_t addr); +uint64_t ldq_phys(target_phys_addr_t addr); +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); +void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val); +void stb_phys(target_phys_addr_t addr, uint32_t val); +void stw_phys(target_phys_addr_t addr, uint32_t val); +void stl_phys(target_phys_addr_t addr, uint32_t val); +void stq_phys(target_phys_addr_t addr, uint64_t val); + +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len); + +#define IO_MEM_SHIFT 3 + +#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) +#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT) + +/* Acts like a ROM when read and like a device when written. */ +#define IO_MEM_ROMD (1) +#define IO_MEM_SUBPAGE (2) +#define IO_MEM_SUBWIDTH (4) + +#endif /* !CPU_COMMON_H */ diff --git a/qemu/qemu-git/.svn/text-base/cpu-defs.h.svn-base b/qemu/qemu-git/.svn/text-base/cpu-defs.h.svn-base new file mode 100644 index 0000000..95068b5 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cpu-defs.h.svn-base @@ -0,0 +1,202 @@ +/* + * common defines for all CPUs + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_DEFS_H +#define CPU_DEFS_H + +#ifndef NEED_CPU_H +#error cpu.h included from common code +#endif + +#include "config.h" +#include +#include +#include +#include "osdep.h" +#include "qemu-queue.h" +#include "targphys.h" + +#ifndef TARGET_LONG_BITS +#error TARGET_LONG_BITS must be defined before including this header +#endif + +#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) + +/* target_ulong is the type of a virtual address */ +#if TARGET_LONG_SIZE == 4 +typedef int32_t target_long; +typedef uint32_t target_ulong; +#define TARGET_FMT_lx "%08x" +#define TARGET_FMT_ld "%d" +#define TARGET_FMT_lu "%u" +#elif TARGET_LONG_SIZE == 8 +typedef int64_t target_long; +typedef uint64_t target_ulong; +#define TARGET_FMT_lx "%016" PRIx64 +#define TARGET_FMT_ld "%" PRId64 +#define TARGET_FMT_lu "%" PRIu64 +#else +#error TARGET_LONG_SIZE undefined +#endif + +#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) + +#define EXCP_INTERRUPT 0x10000 /* async interruption */ +#define EXCP_HLT 0x10001 /* hlt instruction reached */ +#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ +#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ + +#define TB_JMP_CACHE_BITS 12 +#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) + +/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for + addresses on the same page. The top bits are the same. This allows + TLB invalidation to quickly clear a subset of the hash table. */ +#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2) +#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS) +#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1) +#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE) + +#define CPU_TLB_BITS 8 +#define CPU_TLB_SIZE (1 << CPU_TLB_BITS) + +#if TARGET_PHYS_ADDR_BITS == 32 && TARGET_LONG_BITS == 32 +#define CPU_TLB_ENTRY_BITS 4 +#else +#define CPU_TLB_ENTRY_BITS 5 +#endif + +typedef struct CPUTLBEntry { + /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address + bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not + go directly to ram. + bit 3 : indicates that the entry is invalid + bit 2..0 : zero + */ + target_ulong addr_read; + target_ulong addr_write; + target_ulong addr_code; + /* Addend to virtual address to get physical address. IO accesses + use the corresponding iotlb value. */ +#if TARGET_PHYS_ADDR_BITS == 64 + /* on i386 Linux make sure it is aligned */ + target_phys_addr_t addend __attribute__((aligned(8))); +#else + target_phys_addr_t addend; +#endif + /* padding to get a power of two size */ + uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) - + (sizeof(target_ulong) * 3 + + ((-sizeof(target_ulong) * 3) & (sizeof(target_phys_addr_t) - 1)) + + sizeof(target_phys_addr_t))]; +} CPUTLBEntry; + +#ifdef HOST_WORDS_BIGENDIAN +typedef struct icount_decr_u16 { + uint16_t high; + uint16_t low; +} icount_decr_u16; +#else +typedef struct icount_decr_u16 { + uint16_t low; + uint16_t high; +} icount_decr_u16; +#endif + +struct kvm_run; +struct KVMState; + +typedef struct CPUBreakpoint { + target_ulong pc; + int flags; /* BP_* */ + QTAILQ_ENTRY(CPUBreakpoint) entry; +} CPUBreakpoint; + +typedef struct CPUWatchpoint { + target_ulong vaddr; + target_ulong len_mask; + int flags; /* BP_* */ + QTAILQ_ENTRY(CPUWatchpoint) entry; +} CPUWatchpoint; + +#define CPU_TEMP_BUF_NLONGS 128 +#define CPU_COMMON \ + struct TranslationBlock *current_tb; /* currently executing TB */ \ + /* soft mmu support */ \ + /* in order to avoid passing too many arguments to the MMIO \ + helpers, we store some rarely used information in the CPU \ + context) */ \ + unsigned long mem_io_pc; /* host pc at which the memory was \ + accessed */ \ + target_ulong mem_io_vaddr; /* target virtual addr at which the \ + memory was accessed */ \ + uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ + uint32_t stop; /* Stop request */ \ + uint32_t stopped; /* Artificially stopped */ \ + uint32_t interrupt_request; \ + volatile sig_atomic_t exit_request; \ + /* The meaning of the MMU modes is defined in the target code. */ \ + CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ + target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \ + struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ + /* buffer for temporaries in the code generator */ \ + long temp_buf[CPU_TEMP_BUF_NLONGS]; \ + \ + int64_t icount_extra; /* Instructions until next timer event. */ \ + /* Number of cycles left, with interrupt flag in high bit. \ + This allows a single read-compare-cbranch-write sequence to test \ + for both decrementer underflow and exceptions. */ \ + union { \ + uint32_t u32; \ + icount_decr_u16 u16; \ + } icount_decr; \ + uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \ + \ + /* from this point: preserved by CPU reset */ \ + /* ice debug support */ \ + QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \ + int singlestep_enabled; \ + \ + QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \ + CPUWatchpoint *watchpoint_hit; \ + \ + struct GDBRegisterState *gdb_regs; \ + \ + /* Core interrupt code */ \ + jmp_buf jmp_env; \ + int exception_index; \ + \ + CPUState *next_cpu; /* next CPU sharing TB cache */ \ + int cpu_index; /* CPU index (informative) */ \ + uint32_t host_tid; /* host thread ID */ \ + int numa_node; /* NUMA node this cpu is belonging to */ \ + int nr_cores; /* number of cores within this CPU package */ \ + int nr_threads;/* number of threads within this CPU */ \ + int running; /* Nonzero if cpu is currently running(usermode). */ \ + /* user data */ \ + void *opaque; \ + \ + uint32_t created; \ + struct QemuThread *thread; \ + struct QemuCond *halt_cond; \ + const char *cpu_model_str; \ + struct KVMState *kvm_state; \ + struct kvm_run *kvm_run; \ + int kvm_fd; + +#endif diff --git a/qemu/qemu-git/.svn/text-base/cpu-exec.c.svn-base b/qemu/qemu-git/.svn/text-base/cpu-exec.c.svn-base new file mode 100644 index 0000000..4635be3 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cpu-exec.c.svn-base @@ -0,0 +1,1201 @@ +/* + * i386 emulator main execution loop + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#include "exec.h" +#include "disas.h" +#include "tcg.h" +#include "kvm.h" + +#if !defined(CONFIG_SOFTMMU) +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#include +#ifdef __linux__ +#include +#endif +#endif + +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +// Work around ugly bugs in glibc that mangle global register contents +#undef env +#define env cpu_single_env +#endif + +int tb_invalidated_flag; + +//#define CONFIG_DEBUG_EXEC +//#define DEBUG_SIGNAL + +int qemu_cpu_has_work(CPUState *env) +{ + return cpu_has_work(env); +} + +void cpu_loop_exit(void) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ + regs_to_env(); + longjmp(env->jmp_env, 1); +} + +/* exit the current TB from a signal handler. The host registers are + restored in a state compatible with the CPU emulator + */ +void cpu_resume_from_signal(CPUState *env1, void *puc) +{ +#if !defined(CONFIG_SOFTMMU) +#ifdef __linux__ + struct ucontext *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#endif +#endif + + env = env1; + + /* XXX: restore cpu registers saved in host registers */ + +#if !defined(CONFIG_SOFTMMU) + if (puc) { + /* XXX: use siglongjmp ? */ +#ifdef __linux__ + sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); +#elif defined(__OpenBSD__) + sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); +#endif + } +#endif + env->exception_index = -1; + longjmp(env->jmp_env, 1); +} + +/* Execute the code without caching the generated code. An interpreter + could be used if available. */ +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +{ + unsigned long next_tb; + TranslationBlock *tb; + + /* Should never happen. + We only end up here when an existing TB is too long. */ + if (max_cycles > CF_COUNT_MASK) + max_cycles = CF_COUNT_MASK; + + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, + max_cycles); + env->current_tb = tb; + /* execute the generated code */ + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + + if ((next_tb & 3) == 2) { + /* Restore PC. This may happen if async event occurs before + the TB starts executing. */ + cpu_pc_from_tb(env, tb); + } + tb_phys_invalidate(tb, -1); + tb_free(tb); +} + +static TranslationBlock *tb_find_slow(target_ulong pc, + target_ulong cs_base, + uint64_t flags) +{ + TranslationBlock *tb, **ptb1; + unsigned int h; + target_ulong phys_pc, phys_page1, phys_page2, virt_page2; + + tb_invalidated_flag = 0; + + regs_to_env(); /* XXX: do it just before cpu_gen_code() */ + + /* find translated block using physical mappings */ + phys_pc = get_phys_addr_code(env, pc); + phys_page1 = phys_pc & TARGET_PAGE_MASK; + phys_page2 = -1; + h = tb_phys_hash_func(phys_pc); + ptb1 = &tb_phys_hash[h]; + for(;;) { + tb = *ptb1; + if (!tb) + goto not_found; + if (tb->pc == pc && + tb->page_addr[0] == phys_page1 && + tb->cs_base == cs_base && + tb->flags == flags) { + /* check next page if needed */ + if (tb->page_addr[1] != -1) { + virt_page2 = (pc & TARGET_PAGE_MASK) + + TARGET_PAGE_SIZE; + phys_page2 = get_phys_addr_code(env, virt_page2); + if (tb->page_addr[1] == phys_page2) + goto found; + } else { + goto found; + } + } + ptb1 = &tb->phys_hash_next; + } + not_found: + /* if no translated code available, then translate it now */ + tb = tb_gen_code(env, pc, cs_base, flags, 0); + + found: + /* we add the TB in the virtual pc hash table */ + env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; + return tb; +} + +static inline TranslationBlock *tb_find_fast(void) +{ + TranslationBlock *tb; + target_ulong cs_base, pc; + int flags; + + /* we record a subset of the CPU state. It will + always be the same before a given translated block + is executed. */ + cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); + tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; + if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || + tb->flags != flags)) { + tb = tb_find_slow(pc, cs_base, flags); + } + return tb; +} + +static CPUDebugExcpHandler *debug_excp_handler; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) +{ + CPUDebugExcpHandler *old_handler = debug_excp_handler; + + debug_excp_handler = handler; + return old_handler; +} + +static void cpu_handle_debug_exception(CPUState *env) +{ + CPUWatchpoint *wp; + + if (!env->watchpoint_hit) + QTAILQ_FOREACH(wp, &env->watchpoints, entry) + wp->flags &= ~BP_WATCHPOINT_HIT; + + if (debug_excp_handler) + debug_excp_handler(env); +} + +/* main execution loop */ + +int cpu_exec(CPUState *env1) +{ +#define DECLARE_HOST_REGS 1 +#include "hostregs_helper.h" + int ret, interrupt_request; + TranslationBlock *tb; + uint8_t *tc_ptr; + unsigned long next_tb; + + if (cpu_halted(env1) == EXCP_HALTED) + return EXCP_HALTED; + + cpu_single_env = env1; + + /* first we save global registers */ +#define SAVE_HOST_REGS 1 +#include "hostregs_helper.h" + env = env1; + + env_to_regs(); +#if defined(TARGET_I386) + /* put eflags in CPU temporary format */ + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_SPARC) +#elif defined(TARGET_M68K) + env->cc_op = CC_OP_FLAGS; + env->cc_dest = env->sr & 0xf; + env->cc_x = (env->sr >> 4) & 1; +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_ARM) +#elif defined(TARGET_PPC) +#elif defined(TARGET_MICROBLAZE) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) +#elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) + /* XXXXX */ +#else +#error unsupported target CPU +#endif + env->exception_index = -1; + + /* prepare setjmp context for exception handling */ + for(;;) { + if (setjmp(env->jmp_env) == 0) { +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + env->current_tb = NULL; + /* if an exception is pending, we execute it here */ + if (env->exception_index >= 0) { + if (env->exception_index >= EXCP_INTERRUPT) { + /* exit request from the cpu execution loop */ + ret = env->exception_index; + if (ret == EXCP_DEBUG) + cpu_handle_debug_exception(env); + break; + } else { +#if defined(CONFIG_USER_ONLY) + /* if user mode only, we simulate a fake exception + which will be handled outside the cpu execution + loop */ +#if defined(TARGET_I386) + do_interrupt_user(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; +#endif + ret = env->exception_index; + break; +#else +#if defined(TARGET_I386) + /* simulate a real cpu exception. On i386, it can + trigger new exceptions, but we do not handle + double or triple faults yet. */ + do_interrupt(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; +#elif defined(TARGET_PPC) + do_interrupt(env); +#elif defined(TARGET_MICROBLAZE) + do_interrupt(env); +#elif defined(TARGET_MIPS) + do_interrupt(env); +#elif defined(TARGET_SPARC) + do_interrupt(env); +#elif defined(TARGET_ARM) + do_interrupt(env); +#elif defined(TARGET_SH4) + do_interrupt(env); +#elif defined(TARGET_ALPHA) + do_interrupt(env); +#elif defined(TARGET_CRIS) + do_interrupt(env); +#elif defined(TARGET_M68K) + do_interrupt(0); +#endif +#endif + } + env->exception_index = -1; + } + + if (kvm_enabled()) { + kvm_cpu_exec(env); + longjmp(env->jmp_env, 1); + } + + next_tb = 0; /* force lookup of first TB */ + for(;;) { + interrupt_request = env->interrupt_request; + if (unlikely(interrupt_request)) { + if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) { + /* Mask out external interrupts for this step. */ + interrupt_request &= ~(CPU_INTERRUPT_HARD | + CPU_INTERRUPT_FIQ | + CPU_INTERRUPT_SMI | + CPU_INTERRUPT_NMI); + } + if (interrupt_request & CPU_INTERRUPT_DEBUG) { + env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); + } +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ + defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ + defined(TARGET_MICROBLAZE) + if (interrupt_request & CPU_INTERRUPT_HALT) { + env->interrupt_request &= ~CPU_INTERRUPT_HALT; + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } +#endif +#if defined(TARGET_I386) + if (interrupt_request & CPU_INTERRUPT_INIT) { + svm_check_intercept(SVM_EXIT_INIT); + do_cpu_init(env); + env->exception_index = EXCP_HALTED; + cpu_loop_exit(); + } else if (interrupt_request & CPU_INTERRUPT_SIPI) { + do_cpu_sipi(env); + } else if (env->hflags2 & HF2_GIF_MASK) { + if ((interrupt_request & CPU_INTERRUPT_SMI) && + !(env->hflags & HF_SMM_MASK)) { + svm_check_intercept(SVM_EXIT_SMI); + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_NMI) && + !(env->hflags2 & HF2_NMI_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_NMI; + env->hflags2 |= HF2_NMI_MASK; + do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + next_tb = 0; + } else if (interrupt_request & CPU_INTERRUPT_MCE) { + env->interrupt_request &= ~CPU_INTERRUPT_MCE; + do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (((env->hflags2 & HF2_VINTR_MASK) && + (env->hflags2 & HF2_HIF_MASK)) || + (!(env->hflags2 & HF2_VINTR_MASK) && + (env->eflags & IF_MASK && + !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { + int intno; + svm_check_intercept(SVM_EXIT_INTR); + env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); + intno = cpu_get_pic_interrupt(env); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; +#if !defined(CONFIG_USER_ONLY) + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { + int intno; + /* FIXME: this should respect TPR */ + svm_check_intercept(SVM_EXIT_VINTR); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno); + do_interrupt(intno, 0, 0, 0, 1); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + next_tb = 0; +#endif + } + } +#elif defined(TARGET_PPC) +#if 0 + if ((interrupt_request & CPU_INTERRUPT_RESET)) { + cpu_reset(env); + } +#endif + if (interrupt_request & CPU_INTERRUPT_HARD) { + ppc_hw_interrupt(env); + if (env->pending_interrupts == 0) + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + next_tb = 0; + } +#elif defined(TARGET_MICROBLAZE) + if ((interrupt_request & CPU_INTERRUPT_HARD) + && (env->sregs[SR_MSR] & MSR_IE) + && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) + && !(env->iflags & (D_FLAG | IMM_FLAG))) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_MIPS) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && + (env->CP0_Status & (1 << CP0St_IE)) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + /* Raise it */ + env->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_SPARC) + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && + env->interrupt_index > 0) { + int pil = env->interrupt_index & 0xf; + int type = env->interrupt_index & 0xf0; + + if (((type == TT_EXTINT) && + cpu_pil_allowed(env, pil)) || + type != TT_EXTINT) { + env->exception_index = env->interrupt_index; + do_interrupt(env); + next_tb = 0; + } + } + } else if (interrupt_request & CPU_INTERRUPT_TIMER) { + //do_interrupt(0, 0, 0, 0, 0); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + } +#elif defined(TARGET_ARM) + if (interrupt_request & CPU_INTERRUPT_FIQ + && !(env->uncached_cpsr & CPSR_F)) { + env->exception_index = EXCP_FIQ; + do_interrupt(env); + next_tb = 0; + } + /* ARMv7-M interrupt return works by loading a magic value + into the PC. On real hardware the load causes the + return to occur. The qemu implementation performs the + jump normally, then does the exception return when the + CPU tries to execute code at the magic address. + This will cause the magic PC value to be pushed to + the stack if an interrupt occured at the wrong time. + We avoid this by disabling interrupts when + pc contains a magic address. */ + if (interrupt_request & CPU_INTERRUPT_HARD + && ((IS_M(env) && env->regs[15] < 0xfffffff0) + || !(env->uncached_cpsr & CPSR_I))) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_SH4) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_ALPHA) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_CRIS) + if (interrupt_request & CPU_INTERRUPT_HARD + && (env->pregs[PR_CCS] & I_FLAG)) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } + if (interrupt_request & CPU_INTERRUPT_NMI + && (env->pregs[PR_CCS] & M_FLAG)) { + env->exception_index = EXCP_NMI; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_M68K) + if (interrupt_request & CPU_INTERRUPT_HARD + && ((env->sr & SR_I) >> SR_I_SHIFT) + < env->pending_level) { + /* Real hardware gets the interrupt vector via an + IACK cycle at this point. Current emulated + hardware doesn't rely on this, so we + provide/save the vector when the interrupt is + first signalled. */ + env->exception_index = env->pending_vector; + do_interrupt(1); + next_tb = 0; + } +#endif + /* Don't use the cached interupt_request value, + do_interrupt may have updated the EXITTB flag. */ + if (env->interrupt_request & CPU_INTERRUPT_EXITTB) { + env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; + } + } + if (unlikely(env->exit_request)) { + env->exit_request = 0; + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); + } +#ifdef CONFIG_DEBUG_EXEC + if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { + /* restore flags in standard format */ + regs_to_env(); +#if defined(TARGET_I386) + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); + log_cpu_state(env, X86_DUMP_CCOP); + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_ARM) + log_cpu_state(env, 0); +#elif defined(TARGET_SPARC) + log_cpu_state(env, 0); +#elif defined(TARGET_PPC) + log_cpu_state(env, 0); +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); + log_cpu_state(env, 0); +#elif defined(TARGET_MICROBLAZE) + log_cpu_state(env, 0); +#elif defined(TARGET_MIPS) + log_cpu_state(env, 0); +#elif defined(TARGET_SH4) + log_cpu_state(env, 0); +#elif defined(TARGET_ALPHA) + log_cpu_state(env, 0); +#elif defined(TARGET_CRIS) + log_cpu_state(env, 0); +#else +#error unsupported target CPU +#endif + } +#endif + spin_lock(&tb_lock); + tb = tb_find_fast(); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ + if (tb_invalidated_flag) { + /* as some TB could have been invalidated because + of memory exceptions while generating the code, we + must recompute the hash index here */ + next_tb = 0; + tb_invalidated_flag = 0; + } +#ifdef CONFIG_DEBUG_EXEC + qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", + (long)tb->tc_ptr, tb->pc, + lookup_symbol(tb->pc)); +#endif + /* see if we can patch the calling TB. When the TB + spans two pages, we cannot safely do a direct + jump. */ + { + if (next_tb != 0 && tb->page_addr[1] == -1) { + tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); + } + } + spin_unlock(&tb_lock); + env->current_tb = tb; + + /* cpu_interrupt might be called while translating the + TB, but before it is linked into a potentially + infinite loop and becomes env->current_tb. Avoid + starting execution if there is a pending interrupt. */ + if (unlikely (env->exit_request)) + env->current_tb = NULL; + + while (env->current_tb) { + tc_ptr = tb->tc_ptr; + /* execute the generated code */ +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + next_tb = tcg_qemu_tb_exec(tc_ptr); + env->current_tb = NULL; + if ((next_tb & 3) == 2) { + /* Instruction counter expired. */ + int insns_left; + tb = (TranslationBlock *)(long)(next_tb & ~3); + /* Restore PC. */ + cpu_pc_from_tb(env, tb); + insns_left = env->icount_decr.u32; + if (env->icount_extra && insns_left >= 0) { + /* Refill decrementer and continue execution. */ + env->icount_extra += insns_left; + if (env->icount_extra > 0xffff) { + insns_left = 0xffff; + } else { + insns_left = env->icount_extra; + } + env->icount_extra -= insns_left; + env->icount_decr.u16.low = insns_left; + } else { + if (insns_left > 0) { + /* Execute remaining instructions. */ + cpu_exec_nocache(insns_left, tb); + } + env->exception_index = EXCP_INTERRUPT; + next_tb = 0; + cpu_loop_exit(); + } + } + } + /* reset soft MMU for next block (it can currently + only be set by a memory fault) */ + } /* for(;;) */ + } else { + env_to_regs(); + } + } /* for(;;) */ + + +#if defined(TARGET_I386) + /* restore flags in standard format */ + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); +#elif defined(TARGET_ARM) + /* XXX: Save/restore host fpu exception state?. */ +#elif defined(TARGET_SPARC) +#elif defined(TARGET_PPC) +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); +#elif defined(TARGET_MICROBLAZE) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) + /* XXXXX */ +#else +#error unsupported target CPU +#endif + + /* restore global registers */ +#include "hostregs_helper.h" + + /* fail safe : never use cpu_single_env outside cpu_exec() */ + cpu_single_env = NULL; + return ret; +} + +/* must only be called from the generated code as an exception can be + generated */ +void tb_invalidate_page_range(target_ulong start, target_ulong end) +{ + /* XXX: cannot enable it yet because it yields to MMU exception + where NIP != read address on PowerPC */ +#if 0 + target_ulong phys_addr; + phys_addr = get_phys_addr_code(env, start); + tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0); +#endif +} + +#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY) + +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (selector << 4), 0xffff, 0); + } else { + helper_load_seg(seg_reg, selector); + } + env = saved_env; +} + +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_fsave(ptr, data32); + + env = saved_env; +} + +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_frstor(ptr, data32); + + env = saved_env; +} + +#endif /* TARGET_I386 */ + +#if !defined(CONFIG_SOFTMMU) + +#if defined(TARGET_I386) +#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code) +#else +#define EXCEPTION_ACTION cpu_loop_exit() +#endif + +/* 'pc' is the host PC at which the exception was raised. 'address' is + the effective address of the memory exception. 'is_write' is 1 if a + write caused the exception and otherwise 0'. 'old_set' is the + signal set which should be restored */ +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set, + void *puc) +{ + TranslationBlock *tb; + int ret; + + if (cpu_single_env) + env = cpu_single_env; /* XXX: find a correct solution for multithread */ +#if defined(DEBUG_SIGNAL) + qemu_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(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); + if (ret < 0) + return 0; /* not an MMU fault */ + if (ret == 0) + return 1; /* the MMU fault was handled without causing real CPU fault */ + /* 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, puc); + } + + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + EXCEPTION_ACTION; + + /* never comes here */ + return 1; +} + +#if defined(__i386__) + +#if defined(__APPLE__) +# include + +# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) +# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) +# define ERROR_sig(context) ((context)->uc_mcontext->es.err) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined (__NetBSD__) +# include + +# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP]) +# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined (__FreeBSD__) || defined(__DragonFly__) +# include + +# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip)) +# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +# define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +# define EIP_sig(context) ((context)->sc_eip) +# define TRAP_sig(context) ((context)->sc_trapno) +# define ERROR_sig(context) ((context)->sc_err) +# define MASK_sig(context) ((context)->sc_mask) +#else +# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +# define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + unsigned long pc; + int trapno; + +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#define REG_ERR ERR +#define REG_TRAPNO TRAPNO +#endif + pc = EIP_sig(uc); + trapno = TRAP_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + trapno == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(__x86_64__) + +#ifdef __NetBSD__ +#define PC_sig(context) _UC_MACHINE_PC(context) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +#define PC_sig(context) ((context)->sc_rip) +#define TRAP_sig(context) ((context)->sc_trapno) +#define ERROR_sig(context) ((context)->sc_err) +#define MASK_sig(context) ((context)->sc_mask) +#elif defined (__FreeBSD__) || defined(__DragonFly__) +#include + +#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip)) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) +#else +#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + unsigned long pc; +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + + pc = PC_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + TRAP_sig(uc) == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(_ARCH_PPC) + +/*********************************************************************** + * signal context platform-specific definitions + * From Wine + */ +#ifdef linux +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name) +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) +# define IAR_sig(context) REG_sig(nip, context) /* Program counter */ +# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) /* Count register */ +# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */ +# define LR_sig(context) REG_sig(link, context) /* Link register */ +# define CR_sig(context) REG_sig(ccr, context) /* Condition register */ +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num]) +# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4))) +/* Exception Registers access */ +# define DAR_sig(context) REG_sig(dar, context) +# define DSISR_sig(context) REG_sig(dsisr, context) +# define TRAP_sig(context) REG_sig(trap, context) +#endif /* linux */ + +#ifdef __APPLE__ +# include +typedef struct ucontext SIGCONTEXT; +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name) +# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name) +# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name) +# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name) +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) +# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */ +# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) +# define XER_sig(context) REG_sig(xer, context) /* Link register */ +# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */ +# define CR_sig(context) REG_sig(cr, context) /* Condition register */ +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context) +# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context)) +/* Exception Registers access */ +# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */ +# define DSISR_sig(context) EXCEPREG_sig(dsisr, context) +# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ +#endif /* __APPLE__ */ + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = IAR_sig(uc); + is_write = 0; +#if 0 + /* ppc 4xx case */ + if (DSISR_sig(uc) & 0x00800000) + is_write = 1; +#else + if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) + is_write = 1; +#endif + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__alpha__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + uint32_t *pc = uc->uc_mcontext.sc_pc; + uint32_t insn = *pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster */ + switch (insn >> 26) { + case 0x0d: // stw + case 0x0e: // stb + case 0x0f: // stq_u + case 0x24: // stf + case 0x25: // stg + case 0x26: // sts + case 0x27: // stt + case 0x2c: // stl + case 0x2d: // stq + case 0x2e: // stl_c + case 0x2f: // stq_c + is_write = 1; + } + + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} +#elif defined(__sparc__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + int is_write; + uint32_t insn; +#if !defined(__arch64__) || defined(CONFIG_SOLARIS) + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); + /* XXX: is there a standard glibc define ? */ + unsigned long pc = regs[1]; +#else +#ifdef __linux__ + struct sigcontext *sc = puc; + unsigned long pc = sc->sigc_regs.tpc; + void *sigmask = (void *)sc->sigc_mask; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; + unsigned long pc = uc->sc_pc; + void *sigmask = (void *)(long)uc->sc_mask; +#endif +#endif + + /* XXX: need kernel patch to get write flag faster */ + is_write = 0; + insn = *(uint32_t *)pc; + if ((insn >> 30) == 3) { + switch((insn >> 19) & 0x3f) { + case 0x05: // stb + case 0x15: // stba + case 0x06: // sth + case 0x16: // stha + case 0x04: // st + case 0x14: // sta + case 0x07: // std + case 0x17: // stda + case 0x0e: // stx + case 0x1e: // stxa + case 0x24: // stf + case 0x34: // stfa + case 0x27: // stdf + case 0x37: // stdfa + case 0x26: // stqf + case 0x36: // stqfa + case 0x25: // stfsr + case 0x3c: // casa + case 0x3e: // casxa + is_write = 1; + break; + } + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, sigmask, NULL); +} + +#elif defined(__arm__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + +#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) + pc = uc->uc_mcontext.gregs[R15]; +#else + pc = uc->uc_mcontext.arm_pc; +#endif + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__mc68000) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.gregs[16]; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__ia64) + +#ifndef __ISR_VALID + /* This ought to be in ... */ +# define __ISR_VALID 1 +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long ip; + int is_write = 0; + + ip = uc->uc_mcontext.sc_ip; + switch (host_signum) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + if (info->si_code && (info->si_segvflags & __ISR_VALID)) + /* ISR.W (write-access) is bit 33: */ + is_write = (info->si_isr >> 33) & 1; + break; + + default: + break; + } + return handle_cpu_signal(ip, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__s390__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.psw.addr; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__mips__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + greg_t pc = uc->uc_mcontext.pc; + int is_write; + + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__hppa__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + struct siginfo *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.sc_iaoq[0]; + /* FIXME: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#else + +#error host CPU specific signal handler needed + +#endif + +#endif /* !defined(CONFIG_SOFTMMU) */ diff --git a/qemu/qemu-git/.svn/text-base/create_config.svn-base b/qemu/qemu-git/.svn/text-base/create_config.svn-base new file mode 100644 index 0000000..2f052ae --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/create_config.svn-base @@ -0,0 +1,99 @@ +#!/bin/sh + +echo "/* Automatically generated by create_config - do not modify */" + +while read line; do + +case $line in + VERSION=*) # configuration + version=${line#*=} + echo "#define QEMU_VERSION \"$version\"" + ;; + PKGVERSION=*) # configuration + pkgversion=${line#*=} + echo "#define QEMU_PKGVERSION \"$pkgversion\"" + ;; + ARCH=*) # configuration + arch=${line#*=} + arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'` + echo "#define HOST_$arch_name 1" + ;; + CONFIG_AUDIO_DRIVERS=*) + drivers=${line#*=} + echo "#define CONFIG_AUDIO_DRIVERS \\" + for drv in $drivers; do + echo " &${drv}_audio_driver,\\" + done + echo "" + ;; + CONFIG_BDRV_WHITELIST=*) + echo "#define CONFIG_BDRV_WHITELIST \\" + for drv in ${line#*=}; do + echo " \"${drv}\",\\" + done + echo " NULL" + ;; + CONFIG_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + CONFIG_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; + ARCH=*) # configuration + arch=${line#*=} + arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'` + echo "#define HOST_$arch_name 1" + ;; + HOST_USB=*) + # do nothing + ;; + HOST_CC=*) + # do nothing + ;; + HOST_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + HOST_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; + TARGET_ARCH=*) # configuration + target_arch=${line#*=} + echo "#define TARGET_ARCH \"$target_arch\"" + ;; + TARGET_BASE_ARCH=*) # configuration + target_base_arch=${line#*=} + if [ "$target_base_arch" != "$target_arch" ]; then + base_arch_name=`echo $target_base_arch | tr '[:lower:]' '[:upper:]'` + echo "#define TARGET_$base_arch_name 1" + fi + ;; + TARGET_XML_FILES=*) + # do nothing + ;; + TARGET_ABI_DIR=*) + # do nothing + ;; + TARGET_ARCH2=*) + # do nothing + ;; + TARGET_DIRS=*) + # do nothing + ;; + TARGET_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + TARGET_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; +esac + +done # read diff --git a/qemu/qemu-git/.svn/text-base/cris-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/cris-dis.c.svn-base new file mode 100644 index 0000000..455ba8a --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cris-dis.c.svn-base @@ -0,0 +1,2890 @@ +/* Disassembler code for CRIS. + Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Written by Hans-Peter Nilsson. + + This file is part of the GNU binutils and GDB, the GNU debugger. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "dis-asm.h" +//#include "sysdep.h" +#include "target-cris/opcode-cris.h" +//#include "libiberty.h" + + +void *qemu_malloc(size_t len); /* can't include qemu-common.h here */ + +#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) + +/* cris-opc.c -- Table of opcodes for the CRIS processor. + Copyright 2000, 2001, 2004 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Originally written for GAS 1.38.1 by Mikael Asker. + Reorganized by Hans-Peter Nilsson. + +This file is part of GAS, GDB and the GNU binutils. + +GAS, GDB, and GNU binutils is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, or (at your +option) any later version. + +GAS, GDB, and GNU binutils are distributed in the hope that they will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#ifndef NULL +#define NULL (0) +#endif + +/* This table isn't used for CRISv32 and the size of immediate operands. */ +const struct cris_spec_reg +cris_spec_regs[] = +{ + {"bz", 0, 1, cris_ver_v32p, NULL}, + {"p0", 0, 1, 0, NULL}, + {"vr", 1, 1, 0, NULL}, + {"p1", 1, 1, 0, NULL}, + {"pid", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_warning, NULL}, + {"srs", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_warning, NULL}, + {"wz", 4, 2, cris_ver_v32p, NULL}, + {"p4", 4, 2, 0, NULL}, + {"ccr", 5, 2, cris_ver_v0_10, NULL}, + {"exs", 5, 4, cris_ver_v32p, NULL}, + {"p5", 5, 2, cris_ver_v0_10, NULL}, + {"p5", 5, 4, cris_ver_v32p, NULL}, + {"dcr0",6, 2, cris_ver_v0_3, NULL}, + {"eda", 6, 4, cris_ver_v32p, NULL}, + {"p6", 6, 2, cris_ver_v0_3, NULL}, + {"p6", 6, 4, cris_ver_v32p, NULL}, + {"dcr1/mof", 7, 4, cris_ver_v10p, + "Register `dcr1/mof' with ambiguous size specified. Guessing 4 bytes"}, + {"dcr1/mof", 7, 2, cris_ver_v0_3, + "Register `dcr1/mof' with ambiguous size specified. Guessing 2 bytes"}, + {"mof", 7, 4, cris_ver_v10p, NULL}, + {"dcr1",7, 2, cris_ver_v0_3, NULL}, + {"p7", 7, 4, cris_ver_v10p, NULL}, + {"p7", 7, 2, cris_ver_v0_3, NULL}, + {"dz", 8, 4, cris_ver_v32p, NULL}, + {"p8", 8, 4, 0, NULL}, + {"ibr", 9, 4, cris_ver_v0_10, NULL}, + {"ebp", 9, 4, cris_ver_v32p, NULL}, + {"p9", 9, 4, 0, NULL}, + {"irp", 10, 4, cris_ver_v0_10, NULL}, + {"erp", 10, 4, cris_ver_v32p, NULL}, + {"p10", 10, 4, 0, NULL}, + {"srp", 11, 4, 0, NULL}, + {"p11", 11, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"bar/dtp0", 12, 4, cris_ver_warning, + "Ambiguous register `bar/dtp0' specified"}, + {"nrp", 12, 4, cris_ver_v32p, NULL}, + {"bar", 12, 4, cris_ver_v8_10, NULL}, + {"dtp0",12, 4, cris_ver_v0_3, NULL}, + {"p12", 12, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"dccr/dtp1",13, 4, cris_ver_warning, + "Ambiguous register `dccr/dtp1' specified"}, + {"ccs", 13, 4, cris_ver_v32p, NULL}, + {"dccr",13, 4, cris_ver_v8_10, NULL}, + {"dtp1",13, 4, cris_ver_v0_3, NULL}, + {"p13", 13, 4, 0, NULL}, + {"brp", 14, 4, cris_ver_v3_10, NULL}, + {"usp", 14, 4, cris_ver_v32p, NULL}, + {"p14", 14, 4, cris_ver_v3p, NULL}, + {"usp", 15, 4, cris_ver_v10, NULL}, + {"spc", 15, 4, cris_ver_v32p, NULL}, + {"p15", 15, 4, cris_ver_v10p, NULL}, + {NULL, 0, 0, cris_ver_version_all, NULL} +}; + +/* Add version specifiers to this table when necessary. + The (now) regular coding of register names suggests a simpler + implementation. */ +const struct cris_support_reg cris_support_regs[] = +{ + {"s0", 0}, + {"s1", 1}, + {"s2", 2}, + {"s3", 3}, + {"s4", 4}, + {"s5", 5}, + {"s6", 6}, + {"s7", 7}, + {"s8", 8}, + {"s9", 9}, + {"s10", 10}, + {"s11", 11}, + {"s12", 12}, + {"s13", 13}, + {"s14", 14}, + {"s15", 15}, + {NULL, 0} +}; + +/* All CRIS opcodes are 16 bits. + + - The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + - The args component is a string containing characters symbolically + matching the operands of an instruction. Used for both assembly + and disassembly. + + Operand-matching characters: + [ ] , space + Verbatim. + A The string "ACR" (case-insensitive). + B Not really an operand. It causes a "BDAP -size,SP" prefix to be + output for the PUSH alias-instructions and recognizes a push- + prefix at disassembly. This letter isn't recognized for v32. + Must be followed by a R or P letter. + ! Non-match pattern, will not match if there's a prefix insn. + b Non-matching operand, used for branches with 16-bit + displacement. Only recognized by the disassembler. + c 5-bit unsigned immediate in bits <4:0>. + C 4-bit unsigned immediate in bits <3:0>. + d At assembly, optionally (as in put other cases before this one) + ".d" or ".D" at the start of the operands, followed by one space + character. At disassembly, nothing. + D General register in bits <15:12> and <3:0>. + f List of flags in bits <15:12> and <3:0>. + i 6-bit signed immediate in bits <5:0>. + I 6-bit unsigned immediate in bits <5:0>. + M Size modifier (B, W or D) for CLEAR instructions. + m Size modifier (B, W or D) in bits <5:4> + N A 32-bit dword, like in the difference between s and y. + This has no effect on bits in the opcode. Can also be expressed + as "[pc+]" in input. + n As N, but PC-relative (to the start of the instruction). + o [-128..127] word offset in bits <7:1> and <0>. Used by 8-bit + branch instructions. + O [-128..127] offset in bits <7:0>. Also matches a comma and a + general register after the expression, in bits <15:12>. Used + only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode). + P Special register in bits <15:12>. + p Indicates that the insn is a prefix insn. Must be first + character. + Q As O, but don't relax; force an 8-bit offset. + R General register in bits <15:12>. + r General register in bits <3:0>. + S Source operand in bit <10> and a prefix; a 3-operand prefix + without side-effect. + s Source operand in bits <10> and <3:0>, optionally with a + side-effect prefix, except [pc] (the name, not R15 as in ACR) + isn't allowed for v32 and higher. + T Support register in bits <15:12>. + u 4-bit (PC-relative) unsigned immediate word offset in bits <3:0>. + U Relaxes to either u or n, instruction is assumed LAPCQ or LAPC. + Not recognized at disassembly. + x Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>. + y Like 's' but do not allow an integer at assembly. + Y The difference s-y; only an integer is allowed. + z Size modifier (B or W) in bit <4>. */ + + +/* Please note the order of the opcodes in this table is significant. + The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler might not recognize + them, or may indicate an internal error. + + The disassembler should not normally care about the order of the + opcodes, but will prefer an earlier alternative if the "match-score" + (see cris-dis.c) is computed as equal. + + It should not be significant for proper execution that this table is + in alphabetical order, but please follow that convention for an easy + overview. */ + +const struct cris_opcode +cris_opcodes[] = +{ + {"abs", 0x06B0, 0x0940, "r,R", 0, SIZE_NONE, 0, + cris_abs_op}, + + {"add", 0x0600, 0x09c0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0a00, 0x05c0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, + cris_ver_v32p, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addc", 0x0570, 0x0A80, "r,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addc", 0x09A0, 0x0250, "s,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addi", 0x0540, 0x0A80, "x,r,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"addi", 0x0500, 0x0Ac0, "x,r", 0, SIZE_NONE, 0, + cris_addi_op}, + + /* This collates after "addo", but we want to disassemble as "addoq", + not "addo". */ + {"addoq", 0x0100, 0x0E00, "Q,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addo", 0x0940, 0x0280, "m s,R,A", 0, SIZE_FIELD_SIGNED, + cris_ver_v32p, + cris_not_implemented_op}, + + /* This must be located after the insn above, lest we misinterpret + "addo.b -1,r0,acr" as "addo .b-1,r0,acr". FIXME: Sounds like a + parser bug. */ + {"addo", 0x0100, 0x0E00, "O,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addq", 0x0200, 0x0Dc0, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"adds", 0x0420, 0x0Bc0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"adds", 0x0820, 0x03c0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x03c0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x07c0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"addu", 0x0400, 0x0be0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"addu", 0x0800, 0x03e0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x03e0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x07e0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"and", 0x0700, 0x08C0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x04C0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"andq", 0x0300, 0x0CC0, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"asr", 0x0780, 0x0840, "m r,R", 0, SIZE_NONE, 0, + cris_asr_op}, + + {"asrq", 0x03a0, 0x0c40, "c,R", 0, SIZE_NONE, 0, + cris_asrq_op}, + + {"ax", 0x15B0, 0xEA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + /* FIXME: Should use branch #defines. */ + {"b", 0x0dff, 0x0200, "b", 1, SIZE_NONE, 0, + cris_sixteen_bit_offset_branch_op}, + + {"ba", + BA_QUICK_OPCODE, + 0x0F00+(0xF-CC_A)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* Needs to come after the usual "ba o", which might be relaxed to + this one. */ + {"ba", BA_DWORD_OPCODE, + 0xffff & (~BA_DWORD_OPCODE), "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bas", 0x0EBF, 0x0140, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"basc", 0x0EFF, 0x0100, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bcc", + BRANCH_QUICK_OPCODE+CC_CC*0x1000, + 0x0f00+(0xF-CC_CC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bcs", + BRANCH_QUICK_OPCODE+CC_CS*0x1000, + 0x0f00+(0xF-CC_CS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bdap", + BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS, "pm s,R", 0, SIZE_FIELD_SIGNED, + cris_ver_v0_10, + cris_bdap_prefix}, + + {"bdap", + BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS, "pO", 0, SIZE_NONE, + cris_ver_v0_10, + cris_quick_mode_bdap_prefix}, + + {"beq", + BRANCH_QUICK_OPCODE+CC_EQ*0x1000, + 0x0f00+(0xF-CC_EQ)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* This is deliberately put before "bext" to trump it, even though not + in alphabetical order, since we don't do excluding version checks + for v0..v10. */ + {"bwf", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v10, + cris_eight_bit_offset_branch_op}, + + {"bext", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v0_3, + cris_eight_bit_offset_branch_op}, + + {"bge", + BRANCH_QUICK_OPCODE+CC_GE*0x1000, + 0x0f00+(0xF-CC_GE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bgt", + BRANCH_QUICK_OPCODE+CC_GT*0x1000, + 0x0f00+(0xF-CC_GT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhi", + BRANCH_QUICK_OPCODE+CC_HI*0x1000, + 0x0f00+(0xF-CC_HI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhs", + BRANCH_QUICK_OPCODE+CC_HS*0x1000, + 0x0f00+(0xF-CC_HS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"biap", BIAP_OPCODE, BIAP_Z_BITS, "pm r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_biap_prefix}, + + {"ble", + BRANCH_QUICK_OPCODE+CC_LE*0x1000, + 0x0f00+(0xF-CC_LE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blo", + BRANCH_QUICK_OPCODE+CC_LO*0x1000, + 0x0f00+(0xF-CC_LO)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bls", + BRANCH_QUICK_OPCODE+CC_LS*0x1000, + 0x0f00+(0xF-CC_LS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blt", + BRANCH_QUICK_OPCODE+CC_LT*0x1000, + 0x0f00+(0xF-CC_LT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmi", + BRANCH_QUICK_OPCODE+CC_MI*0x1000, + 0x0f00+(0xF-CC_MI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmod", 0x0ab0, 0x0140, "s,R", 0, SIZE_FIX_32, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0140, "S,D", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0540, "S,R,r", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bne", + BRANCH_QUICK_OPCODE+CC_NE*0x1000, + 0x0f00+(0xF-CC_NE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bound", 0x05c0, 0x0A00, "m r,R", 0, SIZE_NONE, 0, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x09c0, 0x0200, "m s,R", 0, SIZE_FIELD, + cris_ver_v0_10, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x0dcf, 0x0200, "m Y,R", 0, SIZE_FIELD, 0, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0200, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0600, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_bound_op}, + + {"bpl", + BRANCH_QUICK_OPCODE+CC_PL*0x1000, + 0x0f00+(0xF-CC_PL)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"break", 0xe930, 0x16c0, "C", 0, SIZE_NONE, + cris_ver_v3p, + cris_break_op}, + + {"bsb", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v32p, + cris_eight_bit_offset_branch_op}, + + {"bsr", 0xBEBF, 0x4140, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bsrc", 0xBEFF, 0x4100, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bstore", 0x0af0, 0x0100, "s,R", 0, SIZE_FIX_32, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0100, "S,D", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0500, "S,R,r", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"btst", 0x04F0, 0x0B00, "r,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + {"btstq", 0x0380, 0x0C60, "c,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + + {"bvc", + BRANCH_QUICK_OPCODE+CC_VC*0x1000, + 0x0f00+(0xF-CC_VC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bvs", + BRANCH_QUICK_OPCODE+CC_VS*0x1000, + 0x0f00+(0xF-CC_VS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"clear", 0x0670, 0x3980, "M r", 0, SIZE_NONE, 0, + cris_reg_mode_clear_op}, + + {"clear", 0x0A70, 0x3180, "M y", 0, SIZE_NONE, 0, + cris_none_reg_mode_clear_test_op}, + + {"clear", 0x0A70, 0x3180, "M S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"clearf", 0x05F0, 0x0A00, "f", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"cmp", 0x06C0, 0x0900, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpq", 0x02C0, 0x0D00, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"cmps", 0x08e0, 0x0300, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmps", 0x08e0, 0x0300, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"cmpu", 0x08c0, 0x0320, "z s,R" , 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpu", 0x08c0, 0x0320, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"di", 0x25F0, 0xDA0F, "", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"dip", DIP_OPCODE, DIP_Z_BITS, "ps", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_dip_prefix}, + + {"div", 0x0980, 0x0640, "m R,r", 0, SIZE_FIELD, 0, + cris_not_implemented_op}, + + {"dstep", 0x06f0, 0x0900, "r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"ei", 0x25B0, 0xDA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"fidxd", 0x0ab0, 0xf540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"fidxi", 0x0d30, 0xF2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagd", 0x1AB0, 0xE540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagi", 0x1D30, 0xE2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"halt", 0xF930, 0x06CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"jas", 0x09B0, 0x0640, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jas", 0x0DBF, 0x0240, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0B30, 0x04C0, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0F3F, 0x00C0, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jbrc", 0x69b0, 0x9640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA9b0, 0x5640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x29b0, 0xd640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB9b0, 0x4640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xBDBF, 0x4240, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x39b0, 0xc640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0xBB30, 0x44C0, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jsrc", 0xBF3F, 0x40C0, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jump", 0x09b0, 0xF640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", 0x09F0, 0x060F, "P", 0, SIZE_NONE, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_PC_INCR_OPCODE_V32, + (0xffff & ~JUMP_PC_INCR_OPCODE_V32), "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "s", 0, SIZE_FIX_32, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"lapc", 0x0970, 0x0680, "U,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapc", 0x0D7F, 0x0280, "dn,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapcq", 0x0970, 0x0680, "u,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"lsl", 0x04C0, 0x0B00, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lslq", 0x03c0, 0x0C20, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsr", 0x07C0, 0x0800, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsrq", 0x03e0, 0x0C00, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lz", 0x0730, 0x08C0, "r,R", 0, SIZE_NONE, + cris_ver_v3p, + cris_not_implemented_op}, + + {"mcp", 0x07f0, 0x0800, "P,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0640, 0x0980, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0630, 0x09c0, "r,P", 0, SIZE_NONE, 0, + cris_move_to_preg_op}, + + {"move", 0x0670, 0x0980, "P,r", 0, SIZE_NONE, 0, + cris_reg_mode_move_from_preg_op}, + + {"move", 0x0BC0, 0x0000, "m R,y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0BC0, 0x0000, "m D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", + MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS, + "s,P", 0, SIZE_SPEC_REG, 0, + cris_move_to_preg_op}, + + {"move", 0x0A30, 0x01c0, "S,P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"move", 0x0A70, 0x0180, "P,y", 0, SIZE_SPEC_REG, 0, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0A70, 0x0180, "P,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0B70, 0x0480, "r,T", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0F70, 0x0080, "T,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"movem", 0x0BF0, 0x0000, "R,y", 0, SIZE_FIX_32, 0, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BF0, 0x0000, "D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BB0, 0x0040, "s,R", 0, SIZE_FIX_32, 0, + cris_move_mem_to_reg_movem_op}, + + {"movem", 0x0BB0, 0x0040, "S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_mem_to_reg_movem_op}, + + {"moveq", 0x0240, 0x0D80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"movs", 0x0460, 0x0B80, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"movs", 0x0860, 0x0380, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movs", 0x0860, 0x0380, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0440, 0x0Ba0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"movu", 0x0840, 0x03a0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0840, 0x03a0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"mstep", 0x07f0, 0x0800, "r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_dstep_logshift_mstep_neg_not_op}, + + {"muls", 0x0d00, 0x02c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_muls_op}, + + {"mulu", 0x0900, 0x06c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_mulu_op}, + + {"neg", 0x0580, 0x0A40, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"nop", NOP_OPCODE, NOP_Z_BITS, "", 0, SIZE_NONE, + cris_ver_v0_10, + cris_btst_nop_op}, + + {"nop", NOP_OPCODE_V32, NOP_Z_BITS_V32, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_btst_nop_op}, + + {"not", 0x8770, 0x7880, "r", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"or", 0x0740, 0x0880, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0480, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"orq", 0x0340, 0x0C80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"pop", 0x0E6E, 0x0191, "!R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"pop", 0x0e3e, 0x01c1, "!P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"push", 0x0FEE, 0x0011, "BR", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"push", 0x0E7E, 0x0181, "BP", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"rbf", 0x3b30, 0xc0c0, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rbf", 0x3b30, 0xc0c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rfe", 0x2930, 0xD6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfg", 0x4930, 0xB6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfn", 0x5930, 0xA6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ret", 0xB67F, 0x4980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"ret", 0xB9F0, 0x460F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"retb", 0xe67f, 0x1980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"rete", 0xA9F0, 0x560F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"reti", 0xA67F, 0x5980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"retn", 0xC9F0, 0x360F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"sbfs", 0x3b70, 0xc080, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sbfs", 0x3b70, 0xc080, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sa", + 0x0530+CC_A*0x1000, + 0x0AC0+(0xf-CC_A)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"ssb", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_scc_op}, + + {"scc", + 0x0530+CC_CC*0x1000, + 0x0AC0+(0xf-CC_CC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"scs", + 0x0530+CC_CS*0x1000, + 0x0AC0+(0xf-CC_CS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"seq", + 0x0530+CC_EQ*0x1000, + 0x0AC0+(0xf-CC_EQ)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"setf", 0x05b0, 0x0A40, "f", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"sfe", 0x3930, 0xC6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + /* Need to have "swf" in front of "sext" so it is the one displayed in + disassembly. */ + {"swf", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v10, + cris_scc_op}, + + {"sext", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v0_3, + cris_scc_op}, + + {"sge", + 0x0530+CC_GE*0x1000, + 0x0AC0+(0xf-CC_GE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sgt", + 0x0530+CC_GT*0x1000, + 0x0AC0+(0xf-CC_GT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shi", + 0x0530+CC_HI*0x1000, + 0x0AC0+(0xf-CC_HI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shs", + 0x0530+CC_HS*0x1000, + 0x0AC0+(0xf-CC_HS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sle", + 0x0530+CC_LE*0x1000, + 0x0AC0+(0xf-CC_LE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slo", + 0x0530+CC_LO*0x1000, + 0x0AC0+(0xf-CC_LO)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sls", + 0x0530+CC_LS*0x1000, + 0x0AC0+(0xf-CC_LS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slt", + 0x0530+CC_LT*0x1000, + 0x0AC0+(0xf-CC_LT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"smi", + 0x0530+CC_MI*0x1000, + 0x0AC0+(0xf-CC_MI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sne", + 0x0530+CC_NE*0x1000, + 0x0AC0+(0xf-CC_NE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"spl", + 0x0530+CC_PL*0x1000, + 0x0AC0+(0xf-CC_PL)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sub", 0x0680, 0x0940, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0540, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subq", 0x0280, 0x0d40, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"subs", 0x04a0, 0x0b40, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"subs", 0x08a0, 0x0340, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0340, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0740, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subu", 0x0480, 0x0b60, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"subu", 0x0880, 0x0360, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0360, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0760, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"svc", + 0x0530+CC_VC*0x1000, + 0x0AC0+(0xf-CC_VC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"svs", + 0x0530+CC_VS*0x1000, + 0x0AC0+(0xf-CC_VS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + /* The insn "swapn" is the same as "not" and will be disassembled as + such, but the swap* family of mnmonics are generally v8-and-higher + only, so count it in. */ + {"swapn", 0x8770, 0x7880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapw", 0x4770, 0xb880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnw", 0xc770, 0x3880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapb", 0x2770, 0xd880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnb", 0xA770, 0x5880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwb", 0x6770, 0x9880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwb", 0xE770, 0x1880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapr", 0x1770, 0xe880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnr", 0x9770, 0x6880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwr", 0x5770, 0xa880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwr", 0xd770, 0x2880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapbr", 0x3770, 0xc880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnbr", 0xb770, 0x4880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwbr", 0x7770, 0x8880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwbr", 0xf770, 0x0880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"test", 0x0640, 0x0980, "m D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_test_op}, + + {"test", 0x0b80, 0xf040, "m y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_clear_test_op}, + + {"test", 0x0b80, 0xf040, "m S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"xor", 0x07B0, 0x0840, "r,R", 0, SIZE_NONE, 0, + cris_xor_op}, + + {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op} +}; + +/* Condition-names, indexed by the CC_* numbers as found in cris.h. */ +const char * const +cris_cc_strings[] = +{ + "hs", + "lo", + "ne", + "eq", + "vc", + "vs", + "pl", + "mi", + "ls", + "hi", + "ge", + "lt", + "gt", + "le", + "a", + /* This is a placeholder. In v0, this would be "ext". In v32, this + is "sb". See cris_conds15. */ + "wf" +}; + +/* Different names and semantics for condition 1111 (0xf). */ +const struct cris_cond15 cris_cond15s[] = +{ + /* FIXME: In what version did condition "ext" disappear? */ + {"ext", cris_ver_v0_3}, + {"wf", cris_ver_v10}, + {"sb", cris_ver_v32p}, + {NULL, 0} +}; + + +/* + * Local variables: + * eval: (c-set-style "gnu") + * indent-tabs-mode: t + * End: + */ + + +/* No instruction will be disassembled longer than this. In theory, and + in silicon, address prefixes can be cascaded. In practice, cascading + is not used by GCC, and not supported by the assembler. */ +#ifndef MAX_BYTES_PER_CRIS_INSN +#define MAX_BYTES_PER_CRIS_INSN 8 +#endif + +/* Whether or not to decode prefixes, folding it into the following + instruction. FIXME: Make this optional later. */ +#ifndef PARSE_PREFIX +#define PARSE_PREFIX 1 +#endif + +/* Sometimes we prefix all registers with this character. */ +#define REGISTER_PREFIX_CHAR '$' + +/* Whether or not to trace the following sequence: + sub* X,r%d + bound* Y,r%d + adds.w [pc+r%d.w],pc + + This is the assembly form of a switch-statement in C. + The "sub is optional. If there is none, then X will be zero. + X is the value of the first case, + Y is the number of cases (including default). + + This results in case offsets printed on the form: + case N: -> case_address + where N is an estimation on the corresponding 'case' operand in C, + and case_address is where execution of that case continues after the + sequence presented above. + + The old style of output was to print the offsets as instructions, + which made it hard to follow "case"-constructs in the disassembly, + and caused a lot of annoying warnings about undefined instructions. + + FIXME: Make this optional later. */ +#ifndef TRACE_CASE +#define TRACE_CASE (disdata->trace_case) +#endif + +enum cris_disass_family + { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 }; + +/* Stored in the disasm_info->private_data member. */ +struct cris_disasm_data +{ + /* Whether to print something less confusing if we find something + matching a switch-construct. */ + bfd_boolean trace_case; + + /* Whether this code is flagged as crisv32. FIXME: Should be an enum + that includes "compatible". */ + enum cris_disass_family distype; +}; + +/* Value of first element in switch. */ +static long case_offset = 0; + +/* How many more case-offsets to print. */ +static long case_offset_counter = 0; + +/* Number of case offsets. */ +static long no_of_case_offsets = 0; + +/* Candidate for next case_offset. */ +static long last_immediate = 0; + +static int cris_constraint + (const char *, unsigned, unsigned, struct cris_disasm_data *); + +/* Parse disassembler options and store state in info. FIXME: For the + time being, we abuse static variables. */ + +static bfd_boolean +cris_parse_disassembler_options (disassemble_info *info, + enum cris_disass_family distype) +{ + struct cris_disasm_data *disdata; + + info->private_data = calloc (1, sizeof (struct cris_disasm_data)); + disdata = (struct cris_disasm_data *) info->private_data; + if (disdata == NULL) + return false; + + /* Default true. */ + disdata->trace_case + = (info->disassembler_options == NULL + || (strcmp (info->disassembler_options, "nocase") != 0)); + + disdata->distype = distype; + return true; +} + +static const struct cris_spec_reg * +spec_reg_info (unsigned int sreg, enum cris_disass_family distype) +{ + int i; + + for (i = 0; cris_spec_regs[i].name != NULL; i++) + { + if (cris_spec_regs[i].number == sreg) + { + if (distype == cris_dis_v32) + switch (cris_spec_regs[i].applicable_version) + { + case cris_ver_warning: + case cris_ver_version_all: + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + /* No ambiguous sizes or register names with CRISv32. */ + if (cris_spec_regs[i].warning == NULL) + return &cris_spec_regs[i]; + default: + ; + } + else if (cris_spec_regs[i].applicable_version != cris_ver_v32p) + return &cris_spec_regs[i]; + } + } + + return NULL; +} + +/* Return the number of bits in the argument. */ + +static int +number_of_bits (unsigned int val) +{ + int bits; + + for (bits = 0; val != 0; val &= val - 1) + bits++; + + return bits; +} + +/* Get an entry in the opcode-table. */ + +static const struct cris_opcode * +get_opcode_entry (unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + /* For non-prefixed insns, we keep a table of pointers, indexed by the + insn code. Each entry is initialized when found to be NULL. */ + static const struct cris_opcode **opc_table = NULL; + + const struct cris_opcode *max_matchedp = NULL; + const struct cris_opcode **prefix_opc_table = NULL; + + /* We hold a table for each prefix that need to be handled differently. */ + static const struct cris_opcode **dip_prefixes = NULL; + static const struct cris_opcode **bdapq_m1_prefixes = NULL; + static const struct cris_opcode **bdapq_m2_prefixes = NULL; + static const struct cris_opcode **bdapq_m4_prefixes = NULL; + static const struct cris_opcode **rest_prefixes = NULL; + + /* Allocate and clear the opcode-table. */ + if (opc_table == NULL) + { + opc_table = qemu_malloc (65536 * sizeof (opc_table[0])); + + memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *)); + + dip_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0])); + + bdapq_m1_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0])); + + bdapq_m2_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0])); + + bdapq_m4_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0])); + + rest_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0])); + } + + /* Get the right table if this is a prefix. + This code is connected to cris_constraints in that it knows what + prefixes play a role in recognition of patterns; the necessary + state is reflected by which table is used. If constraints + involving match or non-match of prefix insns are changed, then this + probably needs changing too. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + const struct cris_opcode *popcodep + = (opc_table[prefix_insn] != NULL + ? opc_table[prefix_insn] + : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata)); + + if (popcodep == NULL) + return NULL; + + if (popcodep->match == BDAP_QUICK_OPCODE) + { + /* Since some offsets are recognized with "push" macros, we + have to have different tables for them. */ + int offset = (prefix_insn & 255); + + if (offset > 127) + offset -= 256; + + switch (offset) + { + case -4: + prefix_opc_table = bdapq_m4_prefixes; + break; + + case -2: + prefix_opc_table = bdapq_m2_prefixes; + break; + + case -1: + prefix_opc_table = bdapq_m1_prefixes; + break; + + default: + prefix_opc_table = rest_prefixes; + break; + } + } + else if (popcodep->match == DIP_OPCODE) + /* We don't allow postincrement when the prefix is DIP, so use a + different table for DIP. */ + prefix_opc_table = dip_prefixes; + else + prefix_opc_table = rest_prefixes; + } + + if (prefix_insn != NO_CRIS_PREFIX + && prefix_opc_table[insn] != NULL) + max_matchedp = prefix_opc_table[insn]; + else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) + max_matchedp = opc_table[insn]; + else + { + const struct cris_opcode *opcodep; + int max_level_of_match = -1; + + for (opcodep = cris_opcodes; + opcodep->name != NULL; + opcodep++) + { + int level_of_match; + + if (disdata->distype == cris_dis_v32) + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + break; + + case cris_ver_v0_3: + case cris_ver_v0_10: + case cris_ver_v3_10: + case cris_ver_sim_v0_10: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_warning: + continue; + + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + break; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + else + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + case cris_ver_v0_3: + case cris_ver_v3p: + case cris_ver_v0_10: + case cris_ver_v8p: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_sim_v0_10: + case cris_ver_v10p: + case cris_ver_warning: + break; + + case cris_ver_v32p: + continue; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + + /* We give a double lead for bits matching the template in + cris_opcodes. Not even, because then "move p8,r10" would + be given 2 bits lead over "clear.d r10". When there's a + tie, the first entry in the table wins. This is + deliberate, to avoid a more complicated recognition + formula. */ + if ((opcodep->match & insn) == opcodep->match + && (opcodep->lose & insn) == 0 + && ((level_of_match + = cris_constraint (opcodep->args, + insn, + prefix_insn, + disdata)) + >= 0) + && ((level_of_match + += 2 * number_of_bits (opcodep->match + | opcodep->lose)) + > max_level_of_match)) + { + max_matchedp = opcodep; + max_level_of_match = level_of_match; + + /* If there was a full match, never mind looking + further. */ + if (level_of_match >= 2 * 16) + break; + } + } + /* Fill in the new entry. + + If there are changes to the opcode-table involving prefixes, and + disassembly then does not work correctly, try removing the + else-clause below that fills in the prefix-table. If that + helps, you need to change the prefix_opc_table setting above, or + something related. */ + if (prefix_insn == NO_CRIS_PREFIX) + opc_table[insn] = max_matchedp; + else + prefix_opc_table[insn] = max_matchedp; + } + + return max_matchedp; +} + +/* Return -1 if the constraints of a bitwise-matched instruction say + that there is no match. Otherwise return a nonnegative number + indicating the confidence in the match (higher is better). */ + +static int +cris_constraint (const char *cs, + unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + int retval = 0; + int tmp; + int prefix_ok = 0; + const char *s; + + for (s = cs; *s; s++) + switch (*s) + { + case '!': + /* Do not recognize "pop" if there's a prefix and then only for + v0..v10. */ + if (prefix_insn != NO_CRIS_PREFIX + || disdata->distype != cris_dis_v0_v10) + return -1; + break; + + case 'U': + /* Not recognized at disassembly. */ + return -1; + + case 'M': + /* Size modifier for "clear", i.e. special register 0, 4 or 8. + Check that it is one of them. Only special register 12 could + be mismatched, but checking for matches is more logical than + checking for mismatches when there are only a few cases. */ + tmp = ((insn >> 12) & 0xf); + if (tmp != 0 && tmp != 4 && tmp != 8) + return -1; + break; + + case 'm': + if ((insn & 0x30) == 0x30) + return -1; + break; + + case 'S': + /* A prefix operand without side-effect. */ + if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) + { + prefix_ok = 1; + break; + } + else + return -1; + + case 's': + case 'y': + case 'Y': + /* If this is a prefixed insn with postincrement (side-effect), + the prefix must not be DIP. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + if (insn & 0x400) + { + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == DIP_OPCODE) + return -1; + } + + prefix_ok = 1; + } + break; + + case 'B': + /* If we don't fall through, then the prefix is ok. */ + prefix_ok = 1; + + /* A "push" prefix. Check for valid "push" size. + In case of special register, it may be != 4. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + /* Match the prefix insn to BDAPQ. */ + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == BDAP_QUICK_OPCODE) + { + int pushsize = (prefix_insn & 255); + + if (pushsize > 127) + pushsize -= 256; + + if (s[1] == 'P') + { + unsigned int spec_reg = (insn >> 12) & 15; + const struct cris_spec_reg *sregp + = spec_reg_info (spec_reg, disdata->distype); + + /* For a special-register, the "prefix size" must + match the size of the register. */ + if (sregp && sregp->reg_size == (unsigned int) -pushsize) + break; + } + else if (s[1] == 'R') + { + if ((insn & 0x30) == 0x20 && pushsize == -4) + break; + } + /* FIXME: Should abort here; next constraint letter + *must* be 'P' or 'R'. */ + } + } + return -1; + + case 'D': + retval = (((insn >> 12) & 15) == (insn & 15)); + if (!retval) + return -1; + else + retval += 4; + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* Since we match four bits, we will give a value of 4-1 = 3 + in a match. If there is a corresponding exact match of a + special register in another pattern, it will get a value of + 4, which will be higher. This should be correct in that an + exact pattern would match better than a general pattern. + + Note that there is a reason for not returning zero; the + pattern for "clear" is partly matched in the bit-pattern + (the two lower bits must be zero), while the bit-pattern + for a move from a special register is matched in the + register constraint. */ + + if (sregp != NULL) + { + retval += 3; + break; + } + else + return -1; + } + } + + if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) + return -1; + + return retval; +} + +/* Format number as hex with a leading "0x" into outbuffer. */ + +static char * +format_hex (unsigned long number, + char *outbuffer, + struct cris_disasm_data *disdata) +{ + /* Truncate negative numbers on >32-bit hosts. */ + number &= 0xffffffff; + + sprintf (outbuffer, "0x%lx", number); + + /* Save this value for the "case" support. */ + if (TRACE_CASE) + last_immediate = number; + + return outbuffer + strlen (outbuffer); +} + +/* Format number as decimal into outbuffer. Parameter signedp says + whether the number should be formatted as signed (!= 0) or + unsigned (== 0). */ + +static char * +format_dec (long number, char *outbuffer, int signedp) +{ + last_immediate = number; + sprintf (outbuffer, signedp ? "%ld" : "%lu", number); + + return outbuffer + strlen (outbuffer); +} + +/* Format the name of the general register regno into outbuffer. */ + +static char * +format_reg (struct cris_disasm_data *disdata, + int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + switch (regno) + { + case 15: + /* For v32, there is no context in which we output PC. */ + if (disdata->distype == cris_dis_v32) + strcpy (outbuffer, "acr"); + else + strcpy (outbuffer, "pc"); + break; + + case 14: + strcpy (outbuffer, "sp"); + break; + + default: + sprintf (outbuffer, "r%d", regno); + break; + } + + return outbuffer_start + strlen (outbuffer_start); +} + +/* Format the name of a support register into outbuffer. */ + +static char * +format_sup_reg (unsigned int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + int i; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + for (i = 0; cris_support_regs[i].name != NULL; i++) + if (cris_support_regs[i].number == regno) + { + sprintf (outbuffer, "%s", cris_support_regs[i].name); + return outbuffer_start + strlen (outbuffer_start); + } + + /* There's supposed to be register names covering all numbers, though + some may be generic names. */ + sprintf (outbuffer, "format_sup_reg-BUG"); + return outbuffer_start + strlen (outbuffer_start); +} + +/* Return the length of an instruction. */ + +static unsigned +bytes_to_skip (unsigned int insn, + const struct cris_opcode *matchedp, + enum cris_disass_family distype, + const struct cris_opcode *prefix_matchedp) +{ + /* Each insn is a word plus "immediate" operands. */ + unsigned to_skip = 2; + const char *template = matchedp->args; + const char *s; + + for (s = template; *s; s++) + if ((*s == 's' || *s == 'N' || *s == 'Y') + && (insn & 0x400) && (insn & 15) == 15 + && prefix_matchedp == NULL) + { + /* Immediate via [pc+], so we have to check the size of the + operand. */ + int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); + + if (matchedp->imm_oprnd_size == SIZE_FIX_32) + to_skip += 4; + else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + return 2; + + /* PC is incremented by two, not one, for a byte. Except on + CRISv32, where constants are always DWORD-size for + special registers. */ + to_skip += + distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; + } + else + to_skip += (mode_size + 1) & ~1; + } + else if (*s == 'n') + to_skip += 4; + else if (*s == 'b') + to_skip += 2; + + return to_skip; +} + +/* Print condition code flags. */ + +static char * +print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp) +{ + /* Use the v8 (Etrax 100) flag definitions for disassembly. + The differences with v0 (Etrax 1..4) vs. Svinto are: + v0 'd' <=> v8 'm' + v0 'e' <=> v8 'b'. + FIXME: Emit v0..v3 flag names somehow. */ + static const char v8_fnames[] = "cvznxibm"; + static const char v32_fnames[] = "cvznxiup"; + const char *fnames + = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames; + + unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); + int i; + + for (i = 0; i < 8; i++) + if (flagbits & (1 << i)) + *cp++ = fnames[i]; + + return cp; +} + +/* Print out an insn with its operands, and update the info->insn_type + fields. The prefix_opcodep and the rest hold a prefix insn that is + supposed to be output as an address mode. */ + +static void +print_with_operands (const struct cris_opcode *opcodep, + unsigned int insn, + unsigned char *buffer, + bfd_vma addr, + disassemble_info *info, + /* If a prefix insn was before this insn (and is supposed + to be output as an address), here is a description of + it. */ + const struct cris_opcode *prefix_opcodep, + unsigned int prefix_insn, + unsigned char *prefix_buffer, + bfd_boolean with_reg_prefix) +{ + /* Get a buffer of somewhat reasonable size where we store + intermediate parts of the insn. */ + char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; + char *tp = temp; + static const char mode_char[] = "bwd?"; + const char *s; + const char *cs; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* Print out the name first thing we do. */ + (*info->fprintf_func) (info->stream, "%s", opcodep->name); + + cs = opcodep->args; + s = cs; + + /* Ignore any prefix indicator. */ + if (*s == 'p') + s++; + + if (*s == 'm' || *s == 'M' || *s == 'z') + { + *tp++ = '.'; + + /* Get the size-letter. */ + *tp++ = *s == 'M' + ? (insn & 0x8000 ? 'd' + : insn & 0x4000 ? 'w' : 'b') + : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; + + /* Ignore the size and the space character that follows. */ + s += 2; + } + + /* Add a space if this isn't a long-branch, because for those will add + the condition part of the name later. */ + if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) + *tp++ = ' '; + + /* Fill in the insn-type if deducible from the name (and there's no + better way). */ + if (opcodep->name[0] == 'j') + { + if (CONST_STRNEQ (opcodep->name, "jsr")) + /* It's "jsr" or "jsrc". */ + info->insn_type = dis_jsr; + else + /* Any other jump-type insn is considered a branch. */ + info->insn_type = dis_branch; + } + + /* We might know some more fields right now. */ + info->branch_delay_insns = opcodep->delayed; + + /* Handle operands. */ + for (; *s; s++) + { + switch (*s) + { + case 'T': + tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'A': + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + *tp++ = 'a'; + *tp++ = 'c'; + *tp++ = 'r'; + break; + + case '[': + case ']': + case ',': + *tp++ = *s; + break; + + case '!': + /* Ignore at this point; used at earlier stages to avoid + recognition if there's a prefix at something that in other + ways looks like a "pop". */ + break; + + case 'd': + /* Ignore. This is an optional ".d " on the large one of + relaxable insns. */ + break; + + case 'B': + /* This was the prefix that made this a "push". We've already + handled it by recognizing it, so signal that the prefix is + handled by setting it to NULL. */ + prefix_opcodep = NULL; + break; + + case 'D': + case 'r': + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + break; + + case 'R': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'n': + { + /* Like N but pc-relative to the start of the insn. */ + unsigned long number + = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000 + addr); + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'u': + { + /* Like n but the offset is bits <3:0> in the instruction. */ + unsigned long number = (buffer[0] & 0xf) * 2 + addr; + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'N': + case 'y': + case 'Y': + case 'S': + case 's': + /* Any "normal" memory operand. */ + if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL) + { + /* We're looking at [pc+], i.e. we need to output an immediate + number, where the size can depend on different things. */ + long number; + int signedp + = ((*cs == 'z' && (insn & 0x20)) + || opcodep->match == BDAP_QUICK_OPCODE); + int nbytes; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + nbytes = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* A NULL return should have been as a non-match earlier, + so catch it as an internal error in the error-case + below. */ + if (sregp == NULL) + /* Whatever non-valid size. */ + nbytes = 42; + else + /* PC is always incremented by a multiple of two. + For CRISv32, immediates are always 4 bytes for + special registers. */ + nbytes = disdata->distype == cris_dis_v32 + ? 4 : (sregp->reg_size + 1) & ~1; + } + else + { + int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + } + + switch (nbytes) + { + case 1: + number = buffer[2]; + if (signedp && number > 127) + number -= 256; + break; + + case 2: + number = buffer[2] + buffer[3] * 256; + if (signedp && number > 32767) + number -= 65536; + break; + + case 4: + number + = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + if ((*cs == 'z' && (insn & 0x20)) + || (opcodep->match == BDAP_QUICK_OPCODE + && (nbytes <= 2 || buffer[1 + nbytes] == 0))) + tp = format_dec (number, tp, signedp); + else + { + unsigned int highbyte = (number >> 24) & 0xff; + + /* Either output this as an address or as a number. If it's + a dword with the same high-byte as the address of the + insn, assume it's an address, and also if it's a non-zero + non-0xff high-byte. If this is a jsr or a jump, then + it's definitely an address. */ + if (nbytes == 4 + && (highbyte == ((addr >> 24) & 0xff) + || (highbyte != 0 && highbyte != 0xff) + || info->insn_type == dis_branch + || info->insn_type == dis_jsr)) + { + /* Finish off and output previous formatted bytes. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + + info->target = number; + } + else + tp = format_hex (number, tp, disdata); + } + } + else + { + /* Not an immediate number. Then this is a (possibly + prefixed) memory operand. */ + if (info->insn_type != dis_nonbranch) + { + int mode_size + = 1 << ((insn >> 4) + & (opcodep->args[0] == 'z' ? 1 : 3)); + int size; + info->insn_type = dis_dref; + info->flags |= CRIS_DIS_FLAG_MEMREF; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + size = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + size = 4; + else + size = sregp->reg_size; + } + else + size = mode_size; + + info->data_size = size; + } + + *tp++ = '['; + + if (prefix_opcodep + /* We don't match dip with a postincremented field + as a side-effect address mode. */ + && ((insn & 0x400) == 0 + || prefix_opcodep->match != DIP_OPCODE)) + { + if (insn & 0x400) + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + *tp++ = '='; + } + + + /* We mainly ignore the prefix format string when the + address-mode syntax is output. */ + switch (prefix_opcodep->match) + { + case DIP_OPCODE: + /* It's [r], [r+] or [pc+]. */ + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + /* It's [pc+]. This cannot possibly be anything + but an address. */ + unsigned long number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + + info->target = (bfd_vma) number; + + /* Finish off and output previous formatted + data. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + /* For a memref in an address, we use target2. + In this case, target is zero. */ + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM); + + info->target2 = prefix_insn & 15; + + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + } + break; + + case BDAP_QUICK_OPCODE: + { + int number; + + number = prefix_buffer[0]; + if (number > 127) + number -= 256; + + /* Output "reg+num" or, if num < 0, "reg-num". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = (prefix_insn >> 12) & 15; + info->target2 = (bfd_vma) number; + break; + } + + case BIAP_OPCODE: + /* Output "r+R.m". */ + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + *tp++ = '+'; + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4 + : ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0))); + + /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */ + if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f) + /* Then start interpreting data as offsets. */ + case_offset_counter = no_of_case_offsets; + break; + + case BDAP_INDIR_OPCODE: + /* Output "r+s.m", or, if "s" is [pc+], "r+s" or + "r-s". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + long number; + unsigned int nbytes; + + /* It's a value. Get its size. */ + int mode_size = 1 << ((prefix_insn >> 4) & 3); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + + switch (nbytes) + { + case 1: + number = prefix_buffer[2]; + if (number > 127) + number -= 256; + break; + + case 2: + number = prefix_buffer[2] + prefix_buffer[3] * 256; + if (number > 32767) + number -= 65536; + break; + + case 4: + number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target2 = (bfd_vma) number; + + /* If the size is dword, then assume it's an + address. */ + if (nbytes == 4) + { + /* Finish off and output previous formatted + bytes. */ + *tp++ = '+'; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + } + } + else + { + /* Output "r+[R].m" or "r+[R+].m". */ + *tp++ = '+'; + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | (((prefix_insn >> 4) == 2) + ? 0 + : (((prefix_insn >> 4) & 3) == 1 + ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD + : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE))); + } + break; + + default: + (*info->fprintf_func) (info->stream, "?prefix-bug"); + } + + /* To mark that the prefix is used, reset it. */ + prefix_opcodep = NULL; + } + else + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = insn & 15; + + if (insn & 0x400) + *tp++ = '+'; + } + *tp++ = ']'; + } + break; + + case 'x': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(insn >> 4) & 3]; + break; + + case 'I': + tp = format_dec (insn & 63, tp, 0); + break; + + case 'b': + { + int where = buffer[2] + buffer[3] * 256; + + if (where > 32767) + where -= 65536; + + where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4); + + if (insn == BA_PC_INCR_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + info->target = (bfd_vma) where; + + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s%s ", + temp, cris_cc_strings[insn >> 12]); + + (*info->print_address_func) ((bfd_vma) where, info); + } + break; + + case 'c': + tp = format_dec (insn & 31, tp, 0); + break; + + case 'C': + tp = format_dec (insn & 15, tp, 0); + break; + + case 'o': + { + long offset = insn & 0xfe; + bfd_vma target; + + if (insn & 1) + offset |= ~0xff; + + if (opcodep->match == BA_QUICK_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset; + info->target = target; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + (*info->print_address_func) (target, info); + } + break; + + case 'Q': + case 'O': + { + long number = buffer[0]; + + if (number > 127) + number = number - 256; + + tp = format_dec (number, tp, 1); + *tp++ = ','; + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + } + break; + + case 'f': + tp = print_flags (disdata, insn, tp); + break; + + case 'i': + tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1); + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + if (sregp->name == NULL) + /* Should have been caught as a non-match eariler. */ + *tp++ = '?'; + else + { + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + strcpy (tp, sregp->name); + tp += strlen (tp); + } + } + break; + + default: + strcpy (tp, "???"); + tp += 3; + } + } + + *tp = 0; + + if (prefix_opcodep) + (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")", + prefix_opcodep->name, prefix_opcodep->args); + + (*info->fprintf_func) (info->stream, "%s", temp); + + /* Get info for matching case-tables, if we don't have any active. + We assume that the last constant seen is used; either in the insn + itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */ + if (TRACE_CASE && case_offset_counter == 0) + { + if (CONST_STRNEQ (opcodep->name, "sub")) + case_offset = last_immediate; + + /* It could also be an "add", if there are negative case-values. */ + else if (CONST_STRNEQ (opcodep->name, "add")) + /* The first case is the negated operand to the add. */ + case_offset = -last_immediate; + + /* A bound insn will tell us the number of cases. */ + else if (CONST_STRNEQ (opcodep->name, "bound")) + no_of_case_offsets = last_immediate + 1; + + /* A jump or jsr or branch breaks the chain of insns for a + case-table, so assume default first-case again. */ + else if (info->insn_type == dis_jsr + || info->insn_type == dis_branch + || info->insn_type == dis_condbranch) + case_offset = 0; + } +} + + +/* Print the CRIS instruction at address memaddr on stream. Returns + length of the instruction, in bytes. Prefix register names with `$' if + WITH_REG_PREFIX. */ + +static int +print_insn_cris_generic (bfd_vma memaddr, + disassemble_info *info, + bfd_boolean with_reg_prefix) +{ + int nbytes; + unsigned int insn; + const struct cris_opcode *matchedp; + int advance = 0; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* No instruction will be disassembled as longer than this number of + bytes; stacked prefixes will not be expanded. */ + unsigned char buffer[MAX_BYTES_PER_CRIS_INSN]; + unsigned char *bufp; + int status = 0; + bfd_vma addr; + + /* There will be an "out of range" error after the last instruction. + Reading pairs of bytes in decreasing number, we hope that we will get + at least the amount that we will consume. + + If we can't get any data, or we do not get enough data, we print + the error message. */ + + nbytes = info->buffer_length; + if (nbytes > MAX_BYTES_PER_CRIS_INSN) + nbytes = MAX_BYTES_PER_CRIS_INSN; + status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); + + /* If we did not get all we asked for, then clear the rest. + Hopefully this makes a reproducible result in case of errors. */ + if (nbytes != MAX_BYTES_PER_CRIS_INSN) + memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes); + + addr = memaddr; + bufp = buffer; + + /* Set some defaults for the insn info. */ + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->flags = 0; + info->target = 0; + info->target2 = 0; + + /* If we got any data, disassemble it. */ + if (nbytes != 0) + { + matchedp = NULL; + + insn = bufp[0] + bufp[1] * 256; + + /* If we're in a case-table, don't disassemble the offsets. */ + if (TRACE_CASE && case_offset_counter != 0) + { + info->insn_type = dis_noninsn; + advance += 2; + + /* If to print data as offsets, then shortcut here. */ + (*info->fprintf_func) (info->stream, "case %ld%s: -> ", + case_offset + no_of_case_offsets + - case_offset_counter, + case_offset_counter == 1 ? "/default" : + ""); + + (*info->print_address_func) ((bfd_vma) + ((short) (insn) + + (long) (addr + - (no_of_case_offsets + - case_offset_counter) + * 2)), info); + case_offset_counter--; + + /* The default case start (without a "sub" or "add") must be + zero. */ + if (case_offset_counter == 0) + case_offset = 0; + } + else if (insn == 0) + { + /* We're often called to disassemble zeroes. While this is a + valid "bcc .+2" insn, it is also useless enough and enough + of a nuiscance that we will just output "bcc .+2" for it + and signal it as a noninsn. */ + (*info->fprintf_func) (info->stream, + disdata->distype == cris_dis_v32 + ? "bcc ." : "bcc .+2"); + info->insn_type = dis_noninsn; + advance += 2; + } + else + { + const struct cris_opcode *prefix_opcodep = NULL; + unsigned char *prefix_buffer = bufp; + unsigned int prefix_insn = insn; + int prefix_size = 0; + + matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata); + + /* Check if we're supposed to write out prefixes as address + modes and if this was a prefix. */ + if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p') + { + /* If it's a prefix, put it into the prefix vars and get the + main insn. */ + prefix_size = bytes_to_skip (prefix_insn, matchedp, + disdata->distype, NULL); + prefix_opcodep = matchedp; + + insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256; + matchedp = get_opcode_entry (insn, prefix_insn, disdata); + + if (matchedp != NULL) + { + addr += prefix_size; + bufp += prefix_size; + advance += prefix_size; + } + else + { + /* The "main" insn wasn't valid, at least not when + prefixed. Put back things enough to output the + prefix insn only, as a normal insn. */ + matchedp = prefix_opcodep; + insn = prefix_insn; + prefix_opcodep = NULL; + } + } + + if (matchedp == NULL) + { + (*info->fprintf_func) (info->stream, "??0x%x", insn); + advance += 2; + + info->insn_type = dis_noninsn; + } + else + { + advance + += bytes_to_skip (insn, matchedp, disdata->distype, + prefix_opcodep); + + /* The info_type and assorted fields will be set according + to the operands. */ + print_with_operands (matchedp, insn, bufp, addr, info, + prefix_opcodep, prefix_insn, + prefix_buffer, with_reg_prefix); + } + } + } + else + info->insn_type = dis_noninsn; + + /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error + status when reading that much, and the insn decoding indicated a + length exceeding what we read, there is an error. */ + if (status != 0 && (nbytes == 0 || advance > nbytes)) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + /* Max supported insn size with one folded prefix insn. */ + info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN; + + /* I would like to set this to a fixed value larger than the actual + number of bytes to print in order to avoid spaces between bytes, + but objdump.c (2.9.1) does not like that, so we print 16-bit + chunks, which is the next choice. */ + info->bytes_per_chunk = 2; + + /* Printing bytes in order of increasing addresses makes sense, + especially on a little-endian target. + This is completely the opposite of what you think; setting this to + BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N + we want. */ + info->display_endian = BFD_ENDIAN_BIG; + + return advance; +} + +/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */ +#if 0 +static int +print_insn_cris_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, true); +} +#endif +/* Disassemble, prefixing register names with `$'. CRIS v32. */ + +static int +print_insn_crisv32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, true); +} + +#if 0 +/* Disassemble, prefixing register names with `$'. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, true); +} + +/* Disassemble, no prefixes on register names. CRIS v0..v10. */ + +static int +print_insn_cris_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, false); +} + +/* Disassemble, no prefixes on register names. CRIS v32. */ + +static int +print_insn_crisv32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, false); +} + +/* Disassemble, no prefixes on register names. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, false); +} +#endif + +int +print_insn_crisv32 (bfd_vma vma, + disassemble_info *info) +{ + return print_insn_crisv32_with_register_prefix(vma, info); +} + +/* Return a disassembler-function that prints registers with a `$' prefix, + or one that prints registers without a prefix. + FIXME: We should improve the solution to avoid the multitude of + functions seen above. */ +#if 0 +disassembler_ftype +cris_get_disassembler (bfd *abfd) +{ + /* If there's no bfd in sight, we return what is valid as input in all + contexts if fed back to the assembler: disassembly *with* register + prefix. Unfortunately this will be totally wrong for v32. */ + if (abfd == NULL) + return print_insn_cris_with_register_prefix; + + if (bfd_get_symbol_leading_char (abfd) == 0) + { + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_with_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_with_register_prefix; + + /* We default to v10. This may be specifically specified in the + bfd mach, but is also the default setting. */ + return print_insn_cris_with_register_prefix; + } + + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_without_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_without_register_prefix; + return print_insn_cris_without_register_prefix; +} +#endif +/* Local variables: + eval: (c-set-style "gnu") + indent-tabs-mode: t + End: */ diff --git a/qemu/qemu-git/.svn/text-base/cutils.c.svn-base b/qemu/qemu-git/.svn/text-base/cutils.c.svn-base new file mode 100644 index 0000000..5b2561c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/cutils.c.svn-base @@ -0,0 +1,237 @@ +/* + * Simple C functions to supplement the C library + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "host-utils.h" + +void pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for(;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +/* strcat and truncate. */ +char *pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +int strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +int stristart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (qemu_toupper(*p) != qemu_toupper(*q)) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +/* XXX: use host strnlen if available ? */ +int qemu_strnlen(const char *s, int max_len) +{ + int i; + + for(i = 0; i < max_len; i++) { + if (s[i] == '\0') { + break; + } + } + return i; +} + +time_t mktimegm(struct tm *tm) +{ + time_t t; + int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; + if (m < 3) { + m += 12; + y--; + } + t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + + y / 400 - 719469); + t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; + return t; +} + +int qemu_fls(int i) +{ + return 32 - clz32(i); +} + +/* + * Make sure data goes on disk, but if possible do not bother to + * write out the inode just for timestamp updates. + * + * Unfortunately even in 2009 many operating systems do not support + * fdatasync and have to fall back to fsync. + */ +int qemu_fdatasync(int fd) +{ +#ifdef CONFIG_FDATASYNC + return fdatasync(fd); +#else + return fsync(fd); +#endif +} + +#ifndef X49GP +/* io vectors */ + +void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint) +{ + qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec)); + qiov->niov = 0; + qiov->nalloc = alloc_hint; + qiov->size = 0; +} + +void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov) +{ + int i; + + qiov->iov = iov; + qiov->niov = niov; + qiov->nalloc = -1; + qiov->size = 0; + for (i = 0; i < niov; i++) + qiov->size += iov[i].iov_len; +} + +void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) +{ + assert(qiov->nalloc != -1); + + if (qiov->niov == qiov->nalloc) { + qiov->nalloc = 2 * qiov->nalloc + 1; + qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec)); + } + qiov->iov[qiov->niov].iov_base = base; + qiov->iov[qiov->niov].iov_len = len; + qiov->size += len; + ++qiov->niov; +} + +/* + * Copies iovecs from src to the end dst until src is completely copied or the + * total size of the copied iovec reaches size. The size of the last copied + * iovec is changed in order to fit the specified total size if it isn't a + * perfect fit already. + */ +void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size) +{ + int i; + size_t done; + + assert(dst->nalloc != -1); + + done = 0; + for (i = 0; (i < src->niov) && (done != size); i++) { + if (done + src->iov[i].iov_len > size) { + qemu_iovec_add(dst, src->iov[i].iov_base, size - done); + break; + } else { + qemu_iovec_add(dst, src->iov[i].iov_base, src->iov[i].iov_len); + } + done += src->iov[i].iov_len; + } +} + +void qemu_iovec_destroy(QEMUIOVector *qiov) +{ + assert(qiov->nalloc != -1); + + qemu_free(qiov->iov); +} + +void qemu_iovec_reset(QEMUIOVector *qiov) +{ + assert(qiov->nalloc != -1); + + qiov->niov = 0; + qiov->size = 0; +} + +void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf) +{ + uint8_t *p = (uint8_t *)buf; + int i; + + for (i = 0; i < qiov->niov; ++i) { + memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); + p += qiov->iov[i].iov_len; + } +} + +void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) +{ + const uint8_t *p = (const uint8_t *)buf; + size_t copy; + int i; + + for (i = 0; i < qiov->niov && count; ++i) { + copy = count; + if (copy > qiov->iov[i].iov_len) + copy = qiov->iov[i].iov_len; + memcpy(qiov->iov[i].iov_base, p, copy); + p += copy; + count -= copy; + } +} +#endif diff --git a/qemu/qemu-git/.svn/text-base/def-helper.h.svn-base b/qemu/qemu-git/.svn/text-base/def-helper.h.svn-base new file mode 100644 index 0000000..8a88c5b --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/def-helper.h.svn-base @@ -0,0 +1,220 @@ +/* Helper file for declaring TCG helper functions. + Should be included at the start and end of target-foo/helper.h. + + Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper + functions. Names should be specified without the helper_ prefix, and + the return and argument types specified. 3 basic types are understood + (i32, i64 and ptr). Additional aliases are provided for convenience and + to match the types used by the C helper implementation. + + The target helper.h should be included in all files that use/define + helper functions. THis will ensure that function prototypes are + consistent. In addition it should be included an extra two times for + helper.c, defining: + GEN_HELPER 1 to produce op generation functions (gen_helper_*) + GEN_HELPER 2 to do runtime registration helper functions. + */ + +#ifndef DEF_HELPER_H +#define DEF_HELPER_H 1 + +#define HELPER(name) glue(helper_, name) + +#define GET_TCGV_i32 GET_TCGV_I32 +#define GET_TCGV_i64 GET_TCGV_I64 +#define GET_TCGV_ptr GET_TCGV_PTR + +/* Some types that make sense in C, but not for TCG. */ +#define dh_alias_i32 i32 +#define dh_alias_s32 i32 +#define dh_alias_int i32 +#define dh_alias_i64 i64 +#define dh_alias_s64 i64 +#define dh_alias_f32 i32 +#define dh_alias_f64 i64 +#if TARGET_LONG_BITS == 32 +#define dh_alias_tl i32 +#else +#define dh_alias_tl i64 +#endif +#define dh_alias_ptr ptr +#define dh_alias_void void +#define dh_alias_env ptr +#define dh_alias(t) glue(dh_alias_, t) + +#define dh_ctype_i32 uint32_t +#define dh_ctype_s32 int32_t +#define dh_ctype_int int +#define dh_ctype_i64 uint64_t +#define dh_ctype_s64 int64_t +#define dh_ctype_f32 float32 +#define dh_ctype_f64 float64 +#define dh_ctype_tl target_ulong +#define dh_ctype_ptr void * +#define dh_ctype_void void +#define dh_ctype_env CPUState * +#define dh_ctype(t) dh_ctype_##t + +/* We can't use glue() here because it falls foul of C preprocessor + recursive expansion rules. */ +#define dh_retvar_decl0_void void +#define dh_retvar_decl0_i32 TCGv_i32 retval +#define dh_retvar_decl0_i64 TCGv_i64 retval +#define dh_retvar_decl0_ptr TCGv_ptr retval +#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t)) + +#define dh_retvar_decl_void +#define dh_retvar_decl_i32 TCGv_i32 retval, +#define dh_retvar_decl_i64 TCGv_i64 retval, +#define dh_retvar_decl_ptr TCGv_ptr retval, +#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t)) + +#define dh_retvar_void TCG_CALL_DUMMY_ARG +#define dh_retvar_i32 GET_TCGV_i32(retval) +#define dh_retvar_i64 GET_TCGV_i64(retval) +#define dh_retvar_ptr GET_TCGV_ptr(retval) +#define dh_retvar(t) glue(dh_retvar_, dh_alias(t)) + +#define dh_is_64bit_void 0 +#define dh_is_64bit_i32 0 +#define dh_is_64bit_i64 1 +#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64) +#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t)) + +#define dh_arg(t, n) \ + args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \ + sizemask |= dh_is_64bit(t) << n + +#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n) + + +#define DEF_HELPER_0(name, ret) \ + DEF_HELPER_FLAGS_0(name, 0, ret) +#define DEF_HELPER_1(name, ret, t1) \ + DEF_HELPER_FLAGS_1(name, 0, ret, t1) +#define DEF_HELPER_2(name, ret, t1, t2) \ + DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2) +#define DEF_HELPER_3(name, ret, t1, t2, t3) \ + DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3) +#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \ + DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4) + +#endif /* DEF_HELPER_H */ + +#ifndef GEN_HELPER +/* Function prototypes. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +dh_ctype(ret) HELPER(name) (void); + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1)); + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)); + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3)); + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ + dh_ctype(t4)); + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == 1 +/* Gen functions. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \ +{ \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 0, NULL); \ +} + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \ +{ \ + TCGArg args[1]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \ +} + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2)) \ +{ \ + TCGArg args[2]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \ +} + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \ +{ \ + TCGArg args[3]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + dh_arg(t3, 3); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 3, args); \ +} + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \ +{ \ + TCGArg args[4]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + dh_arg(t3, 3); \ + dh_arg(t4, 4); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \ +} + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == 2 +/* Register helpers. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +tcg_register_helper(HELPER(name), #name); + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == -1 +/* Undefine macros. */ + +#undef DEF_HELPER_FLAGS_0 +#undef DEF_HELPER_FLAGS_1 +#undef DEF_HELPER_FLAGS_2 +#undef DEF_HELPER_FLAGS_3 +#undef DEF_HELPER_FLAGS_4 +#undef GEN_HELPER + +#endif diff --git a/qemu/qemu-git/.svn/text-base/dis-asm.h.svn-base b/qemu/qemu-git/.svn/text-base/dis-asm.h.svn-base new file mode 100644 index 0000000..5f6f06c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/dis-asm.h.svn-base @@ -0,0 +1,477 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#include +#include +#include +#include +#include + +typedef void *PTR; +typedef uint64_t bfd_vma; +typedef int64_t bfd_signed_vma; +typedef uint8_t bfd_byte; +#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x) +#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x) + +#define BFD64 + +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_evax_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 +#define bfd_mach_cpu32 8 +#define bfd_mach_mcf5200 9 +#define bfd_mach_mcf5206e 10 +#define bfd_mach_mcf5307 11 +#define bfd_mach_mcf5407 12 +#define bfd_mach_mcf528x 13 +#define bfd_mach_mcfv4e 14 +#define bfd_mach_mcf521x 15 +#define bfd_mach_mcf5249 16 +#define bfd_mach_mcf547x 17 +#define bfd_mach_mcf548x 18 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 +/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ +#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ +/* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ + && (mach) != bfd_mach_sparc_sparclite_le) + bfd_arch_mips, /* MIPS Rxxxx */ +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips16 16 + bfd_arch_i386, /* Intel 386 */ +#define bfd_mach_i386_i386 0 +#define bfd_mach_i386_i8086 1 +#define bfd_mach_i386_i386_intel_syntax 2 +#define bfd_mach_x86_64 3 +#define bfd_mach_x86_64_intel_syntax 4 + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 +#define bfd_mach_h8300s 3 + bfd_arch_powerpc, /* PowerPC */ +#define bfd_mach_ppc 0 +#define bfd_mach_ppc64 1 +#define bfd_mach_ppc_403 403 +#define bfd_mach_ppc_403gc 4030 +#define bfd_mach_ppc_e500 500 +#define bfd_mach_ppc_505 505 +#define bfd_mach_ppc_601 601 +#define bfd_mach_ppc_602 602 +#define bfd_mach_ppc_603 603 +#define bfd_mach_ppc_ec603e 6031 +#define bfd_mach_ppc_604 604 +#define bfd_mach_ppc_620 620 +#define bfd_mach_ppc_630 630 +#define bfd_mach_ppc_750 750 +#define bfd_mach_ppc_860 860 +#define bfd_mach_ppc_a35 35 +#define bfd_mach_ppc_rs64ii 642 +#define bfd_mach_ppc_rs64iii 643 +#define bfd_mach_ppc_7400 7400 + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 + bfd_arch_d10v, /* Mitsubishi D10V */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ +#define bfd_mach_sh 1 +#define bfd_mach_sh2 0x20 +#define bfd_mach_sh_dsp 0x2d +#define bfd_mach_sh2a 0x2a +#define bfd_mach_sh2a_nofpu 0x2b +#define bfd_mach_sh2e 0x2e +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_nommu 0x31 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 +#define bfd_mach_sh4_nofpu 0x41 +#define bfd_mach_sh4_nommu_nofpu 0x42 +#define bfd_mach_sh4a 0x4a +#define bfd_mach_sh4a_nofpu 0x4b +#define bfd_mach_sh4al_dsp 0x4d +#define bfd_mach_sh5 0x50 + bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha 1 + bfd_arch_arm, /* Advanced Risc Machines ARM */ +#define bfd_mach_arm_unknown 0 +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 +#define bfd_mach_arm_ep9312 11 +#define bfd_mach_arm_iWMMXt 12 +#define bfd_mach_arm_iWMMXt2 13 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 0 + bfd_arch_arc, /* Argonaut RISC Core */ +#define bfd_mach_arc_base 0 + bfd_arch_m32r, /* Mitsubishi M32R/D */ +#define bfd_mach_m32r 0 /* backwards compatibility */ + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_cris, /* Axis CRIS */ +#define bfd_mach_cris_v0_v10 255 +#define bfd_mach_cris_v32 32 +#define bfd_mach_cris_v10_v32 1032 + bfd_arch_microblaze, /* Xilinx MicroBlaze. */ + bfd_arch_last + }; +#define bfd_mach_s390_31 31 +#define bfd_mach_s390_64 64 + +typedef struct symbol_cache_entry +{ + const char *name; + union + { + PTR p; + bfd_vma i; + } udata; +} asymbol; + +typedef int (*fprintf_ftype) (FILE*, const char*, ...); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + FILE *stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + (int status, bfd_vma memaddr, struct disassemble_info *info); + + /* Function called to print ADDR. */ + void (*print_address_func) + (bfd_vma addr, struct disassemble_info *info); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + (bfd_vma addr, struct disassemble_info * info); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *); + +extern int print_insn_big_mips (bfd_vma, disassemble_info*); +extern int print_insn_little_mips (bfd_vma, disassemble_info*); +extern int print_insn_i386 (bfd_vma, disassemble_info*); +extern int print_insn_m68k (bfd_vma, disassemble_info*); +extern int print_insn_z8001 (bfd_vma, disassemble_info*); +extern int print_insn_z8002 (bfd_vma, disassemble_info*); +extern int print_insn_h8300 (bfd_vma, disassemble_info*); +extern int print_insn_h8300h (bfd_vma, disassemble_info*); +extern int print_insn_h8300s (bfd_vma, disassemble_info*); +extern int print_insn_h8500 (bfd_vma, disassemble_info*); +extern int print_insn_alpha (bfd_vma, disassemble_info*); +extern disassembler_ftype arc_get_disassembler (int, int); +extern int print_insn_arm (bfd_vma, disassemble_info*); +extern int print_insn_sparc (bfd_vma, disassemble_info*); +extern int print_insn_big_a29k (bfd_vma, disassemble_info*); +extern int print_insn_little_a29k (bfd_vma, disassemble_info*); +extern int print_insn_i960 (bfd_vma, disassemble_info*); +extern int print_insn_sh (bfd_vma, disassemble_info*); +extern int print_insn_shl (bfd_vma, disassemble_info*); +extern int print_insn_hppa (bfd_vma, disassemble_info*); +extern int print_insn_m32r (bfd_vma, disassemble_info*); +extern int print_insn_m88k (bfd_vma, disassemble_info*); +extern int print_insn_mn10200 (bfd_vma, disassemble_info*); +extern int print_insn_mn10300 (bfd_vma, disassemble_info*); +extern int print_insn_ns32k (bfd_vma, disassemble_info*); +extern int print_insn_big_powerpc (bfd_vma, disassemble_info*); +extern int print_insn_little_powerpc (bfd_vma, disassemble_info*); +extern int print_insn_rs6000 (bfd_vma, disassemble_info*); +extern int print_insn_w65 (bfd_vma, disassemble_info*); +extern int print_insn_d10v (bfd_vma, disassemble_info*); +extern int print_insn_v850 (bfd_vma, disassemble_info*); +extern int print_insn_tic30 (bfd_vma, disassemble_info*); +extern int print_insn_ppc (bfd_vma, disassemble_info*); +extern int print_insn_s390 (bfd_vma, disassemble_info*); +extern int print_insn_crisv32 (bfd_vma, disassemble_info*); +extern int print_insn_microblaze (bfd_vma, disassemble_info*); + +#if 0 +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler (bfd *); +#endif + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + (bfd_vma, bfd_byte *, int, struct disassemble_info *); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory (int, bfd_vma, struct disassemble_info *); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address (bfd_vma, struct disassemble_info *); + +/* Always true. */ +extern int generic_symbol_at_address (bfd_vma, struct disassemble_info *); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (FPRINTF_FUNC), \ + (INFO).stream = (STREAM), \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).private_data = NULL, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).disassembler_options = NULL, \ + (INFO).insn_info_valid = 0 + +#define _(x) x +#define ATTRIBUTE_UNUSED __attribute__((unused)) + +/* from libbfd */ + +bfd_vma bfd_getl32 (const bfd_byte *addr); +bfd_vma bfd_getb32 (const bfd_byte *addr); +bfd_vma bfd_getl16 (const bfd_byte *addr); +bfd_vma bfd_getb16 (const bfd_byte *addr); +typedef bool bfd_boolean; + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/qemu/qemu-git/.svn/text-base/disas.c.svn-base b/qemu/qemu-git/.svn/text-base/disas.c.svn-base new file mode 100644 index 0000000..28b9398 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/disas.c.svn-base @@ -0,0 +1,416 @@ +/* General "disassemble this chunk" code. Used for debugging. */ +#include "config.h" +#include "dis-asm.h" +#include "elf.h" +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +struct syminfo *syminfos = NULL; + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +static int +target_read_memory (bfd_vma memaddr, + bfd_byte *myaddr, + int length, + struct disassemble_info *info) +{ + cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (bfd_vma addr, struct disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); +} + +/* Just return the given address. */ + +int +generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) +{ + return 1; +} + +bfd_vma bfd_getl32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return (bfd_vma) v; +} + +bfd_vma bfd_getb32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return (bfd_vma) v; +} + +bfd_vma bfd_getl16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + return (bfd_vma) v; +} + +bfd_vma bfd_getb16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + return (bfd_vma) v; +} + +#ifdef TARGET_ARM +static int +print_insn_thumb1(bfd_vma pc, disassemble_info *info) +{ + return print_insn_arm(pc | 1, info); +} +#endif + +/* Disassemble this for me please... (debugging). 'flags' has the following + values: + i386 - nonzero means 16 bit code + arm - nonzero means thumb code + ppc - nonzero means little endian + other targets - unused + */ +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) +{ + target_ulong pc; + int count; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.read_memory_func = target_read_memory; + disasm_info.buffer_vma = code; + disasm_info.buffer_length = size; + +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(TARGET_I386) + if (flags == 2) + disasm_info.mach = bfd_mach_x86_64; + else if (flags == 1) + disasm_info.mach = bfd_mach_i386_i8086; + else + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + if (flags) + print_insn = print_insn_thumb1; + else + print_insn = print_insn_arm; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(TARGET_PPC) + if (flags >> 16) + disasm_info.endian = BFD_ENDIAN_LITTLE; + if (flags & 0xFFFF) { + /* If we have a precise definitions of the instructions set, use it */ + disasm_info.mach = flags & 0xFFFF; + } else { +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif + } + print_insn = print_insn_ppc; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; +#elif defined(TARGET_MIPS) +#ifdef TARGET_WORDS_BIGENDIAN + print_insn = print_insn_big_mips; +#else + print_insn = print_insn_little_mips; +#endif +#elif defined(TARGET_SH4) + disasm_info.mach = bfd_mach_sh4; + print_insn = print_insn_sh; +#elif defined(TARGET_ALPHA) + disasm_info.mach = bfd_mach_alpha; + print_insn = print_insn_alpha; +#elif defined(TARGET_CRIS) + disasm_info.mach = bfd_mach_cris_v32; + print_insn = print_insn_crisv32; +#elif defined(TARGET_MICROBLAZE) + disasm_info.mach = bfd_arch_microblaze; + print_insn = print_insn_microblaze; +#else + fprintf(out, "0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", code); + return; +#endif + + for (pc = code; size > 0; pc += count, size -= count) { + fprintf(out, "0x" TARGET_FMT_lx ": ", pc); + count = print_insn(pc, &disasm_info); +#if 0 + { + int i; + uint8_t b; + fprintf(out, " {"); + for(i = 0; i < count; i++) { + target_read_memory(pc + i, &b, 1, &disasm_info); + fprintf(out, " %02x", b); + } + fprintf(out, " }"); + } +#endif + fprintf(out, "\n"); + if (count < 0) + break; + if (size < count) { + fprintf(out, + "Disassembler disagrees with translator over instruction " + "decoding\n" + "Please report this to qemu-devel@nongnu.org\n"); + break; + } + } +} + +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size) +{ + unsigned long pc; + int count; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.buffer = code; + disasm_info.buffer_vma = (unsigned long)code; + disasm_info.buffer_length = size; + +#ifdef HOST_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(__i386__) + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(__x86_64__) + disasm_info.mach = bfd_mach_x86_64; + print_insn = print_insn_i386; +#elif defined(_ARCH_PPC) + print_insn = print_insn_ppc; +#elif defined(__alpha__) + print_insn = print_insn_alpha; +#elif defined(__sparc__) + print_insn = print_insn_sparc; +#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(__arm__) + print_insn = print_insn_arm; +#elif defined(__MIPSEB__) + print_insn = print_insn_big_mips; +#elif defined(__MIPSEL__) + print_insn = print_insn_little_mips; +#elif defined(__m68k__) + print_insn = print_insn_m68k; +#elif defined(__s390__) + print_insn = print_insn_s390; +#elif defined(__hppa__) + print_insn = print_insn_hppa; +#else + fprintf(out, "0x%lx: Asm output not supported on this arch\n", + (long) code); + return; +#endif + for (pc = (unsigned long)code; size > 0; pc += count, size -= count) { + fprintf(out, "0x%08lx: ", pc); +#ifdef __arm__ + /* since data is included in the code, it is better to + display code data too */ + fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); +#endif + count = print_insn(pc, &disasm_info); + fprintf(out, "\n"); + if (count < 0) + break; + } +} + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(target_ulong orig_addr) +{ + const char *symbol = ""; + struct syminfo *s; + + for (s = syminfos; s; s = s->next) { + symbol = s->lookup_symbol(s, orig_addr); + if (symbol[0] != '\0') { + break; + } + } + + return symbol; +} + +#ifndef X49GP +#if !defined(CONFIG_USER_ONLY) + +#include "monitor.h" + +static int monitor_disas_is_physical; +static CPUState *monitor_disas_env; + +static int +monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) +{ + if (monitor_disas_is_physical) { + cpu_physical_memory_rw(memaddr, myaddr, length, 0); + } else { + cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); + } + return 0; +} + +static int monitor_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + monitor_vprintf((Monitor *)stream, fmt, ap); + va_end(ap); + return 0; +} + +void monitor_disas(Monitor *mon, CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags) +{ + int count, i; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf); + + monitor_disas_env = env; + monitor_disas_is_physical = is_physical; + disasm_info.read_memory_func = monitor_read_memory; + + disasm_info.buffer_vma = pc; + +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(TARGET_I386) + if (flags == 2) + disasm_info.mach = bfd_mach_x86_64; + else if (flags == 1) + disasm_info.mach = bfd_mach_i386_i8086; + else + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + print_insn = print_insn_arm; +#elif defined(TARGET_ALPHA) + print_insn = print_insn_alpha; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(TARGET_PPC) +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif + print_insn = print_insn_ppc; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; +#elif defined(TARGET_MIPS) +#ifdef TARGET_WORDS_BIGENDIAN + print_insn = print_insn_big_mips; +#else + print_insn = print_insn_little_mips; +#endif +#elif defined(TARGET_SH4) + disasm_info.mach = bfd_mach_sh4; + print_insn = print_insn_sh; +#else + monitor_printf(mon, "0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", pc); + return; +#endif + + for(i = 0; i < nb_insn; i++) { + monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc); + count = print_insn(pc, &disasm_info); + monitor_printf(mon, "\n"); + if (count < 0) + break; + pc += count; + } +} +#endif /* !X49GP */ +#endif diff --git a/qemu/qemu-git/.svn/text-base/disas.h.svn-base b/qemu/qemu-git/.svn/text-base/disas.h.svn-base new file mode 100644 index 0000000..06abab2 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/disas.h.svn-base @@ -0,0 +1,41 @@ +#ifndef _QEMU_DISAS_H +#define _QEMU_DISAS_H + +#include "qemu-common.h" + +#ifdef NEED_CPU_H +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size); +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags); + +/* The usual mess... FIXME: Remove this condition once dyngen-exec.h is gone */ +#ifndef __DYNGEN_EXEC_H__ +void monitor_disas(Monitor *mon, CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags); +#endif + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(target_ulong orig_addr); +#endif + +struct syminfo; +struct elf32_sym; +struct elf64_sym; + +typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_phys_addr_t orig_addr); + +struct syminfo { + lookup_symbol_t lookup_symbol; + unsigned int disas_num_syms; + union { + struct elf32_sym *elf32; + struct elf64_sym *elf64; + } disas_symtab; + const char *disas_strtab; + struct syminfo *next; +}; + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +extern struct syminfo *syminfos; + +#endif /* _QEMU_DISAS_H */ diff --git a/qemu/qemu-git/.svn/text-base/dyngen-exec.h.svn-base b/qemu/qemu-git/.svn/text-base/dyngen-exec.h.svn-base new file mode 100644 index 0000000..0353f36 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/dyngen-exec.h.svn-base @@ -0,0 +1,130 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#if !defined(__DYNGEN_EXEC_H__) +#define __DYNGEN_EXEC_H__ + +/* prevent Solaris from trying to typedef FILE in gcc's + include/floatingpoint.h which will conflict with the + definition down below */ +#ifdef __sun__ +#define _FILEDEFED +#endif + +/* NOTE: standard headers should be used with special care at this + point because host CPU registers are used as global variables. Some + host headers do not allow that. */ +#include +#include + +#ifdef __OpenBSD__ +#include +#endif + +/* XXX: This may be wrong for 64-bit ILP32 hosts. */ +typedef void * host_reg_t; + +#ifdef CONFIG_BSD +typedef struct __sFILE FILE; +#else +typedef struct FILE FILE; +#endif +extern int fprintf(FILE *, const char *, ...); +extern int fputs(const char *, FILE *); +extern int printf(const char *, ...); + +#if defined(__i386__) +#define AREG0 "ebp" +#define AREG1 "ebx" +#define AREG2 "esi" +#elif defined(__x86_64__) +#define AREG0 "r14" +#define AREG1 "r15" +#define AREG2 "r12" +#elif defined(_ARCH_PPC) +#define AREG0 "r27" +#define AREG1 "r24" +#define AREG2 "r25" +#elif defined(__arm__) +#define AREG0 "r7" +#define AREG1 "r4" +#define AREG2 "r5" +#elif defined(__hppa__) +#define AREG0 "r17" +#define AREG1 "r14" +#define AREG2 "r15" +#elif defined(__mips__) +#define AREG0 "fp" +#define AREG1 "s0" +#define AREG2 "s1" +#elif defined(__sparc__) +#ifdef CONFIG_SOLARIS +#define AREG0 "g2" +#define AREG1 "g3" +#define AREG2 "g4" +#else +#ifdef __sparc_v9__ +#define AREG0 "g5" +#define AREG1 "g6" +#define AREG2 "g7" +#else +#define AREG0 "g6" +#define AREG1 "g1" +#define AREG2 "g2" +#endif +#endif +#elif defined(__s390__) +#define AREG0 "r10" +#define AREG1 "r7" +#define AREG2 "r8" +#elif defined(__alpha__) +/* Note $15 is the frame pointer, so anything in op-i386.c that would + require a frame pointer, like alloca, would probably loose. */ +#define AREG0 "$15" +#define AREG1 "$9" +#define AREG2 "$10" +#elif defined(__mc68000) +#define AREG0 "%a5" +#define AREG1 "%a4" +#define AREG2 "%d7" +#elif defined(__ia64__) +#define AREG0 "r7" +#define AREG1 "r4" +#define AREG2 "r5" +#else +#error unsupported CPU +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s + +/* The return address may point to the start of the next instruction. + Subtracting one gets us the call instruction itself. */ +#if defined(__s390__) && !defined(__s390x__) +# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) +#elif defined(__arm__) +/* Thumb return addresses have the low bit set, so we need to subtract two. + This is still safe in ARM mode because instructions are 4 bytes. */ +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2)) +#else +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1)) +#endif + +#endif /* !defined(__DYNGEN_EXEC_H__) */ diff --git a/qemu/qemu-git/.svn/text-base/elf.h.svn-base b/qemu/qemu-git/.svn/text-base/elf.h.svn-base new file mode 100644 index 0000000..11674d7 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/elf.h.svn-base @@ -0,0 +1,1193 @@ +#ifndef _QEMU_ELF_H +#define _QEMU_ELF_H + +#include + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_OPTIONS 0x70000001 + +/* Flags in the e_flags field of the header */ +/* MIPS architecture level. */ +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ + +/* The ABI of a file. */ +#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ +#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ + +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ABI2 0x00000020 +#define EF_MIPS_OPTIONS_FIRST 0x00000080 +#define EF_MIPS_32BITMODE 0x00000100 +#define EF_MIPS_ABI 0x0000f000 +#define EF_MIPS_ARCH 0xf0000000 + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 + +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ + +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ + +#define EM_ARM 40 /* ARM */ + +#define EM_SH 42 /* SuperH */ + +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ + +#define EM_IA_64 50 /* HP/Intel IA-64 */ + +#define EM_X86_64 62 /* AMD x86-64 */ + +#define EM_S390 22 /* IBM S/390 */ + +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ + +#define EM_V850 87 /* NEC v850 */ + +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ + +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 + +/* Bogus old v850 magic number, used by old tools. */ +#define EM_CYGNUS_V850 0x9080 + +/* + * This is the old interim value for S/390 architecture + */ +#define EM_S390_OLD 0xA390 + +#define EM_XILINX_MICROBLAZE 0xBAAB + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +/* Symbolic values for the entries in the auxiliary table + put on the initial stack */ +#define AT_NULL 0 /* end of vector */ +#define AT_IGNORE 1 /* entry should be ignored */ +#define AT_EXECFD 2 /* file descriptor of program */ +#define AT_PHDR 3 /* program headers for program */ +#define AT_PHENT 4 /* size of program header entry */ +#define AT_PHNUM 5 /* number of program headers */ +#define AT_PAGESZ 6 /* system page size */ +#define AT_BASE 7 /* base address of interpreter */ +#define AT_FLAGS 8 /* flags */ +#define AT_ENTRY 9 /* entry point of program */ +#define AT_NOTELF 10 /* program is not ELF */ +#define AT_UID 11 /* real uid */ +#define AT_EUID 12 /* effective uid */ +#define AT_GID 13 /* real gid */ +#define AT_EGID 14 /* effective gid */ +#define AT_PLATFORM 15 /* string identifying CPU for optimizations */ +#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_CLKTCK 17 /* frequency at which times() increments */ + +typedef struct dynamic{ + Elf32_Sword d_tag; + union{ + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000) + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + + +/* + * Sparc ELF relocation types + */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 + +/* + * 68k ELF relocation types + */ +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 + +/* + * Alpha ELF relocation types + */ +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_BRSGP 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define SHF_ALPHA_GPREL 0x10000000 + + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#ifndef R_PPC_NUM +#define R_PPC_NUM 37 +#endif + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_NEW_ABI 0x80 +#define EF_OLD_ABI 0x100 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* s390 relocations defined by the ABIs */ +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS + block. */ +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym { + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + + +#define EI_NIDENT 16 + +typedef struct elf32_hdr{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr { + unsigned char e_ident[16]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 +#define SHF_MIPS_GPREL 0x10000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff +#define SHN_MIPS_ACCOMON 0xff00 + +typedef struct elf32_shdr { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr { + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ + + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note { + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note { + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; + +#ifdef ELF_CLASS +#if ELF_CLASS == ELFCLASS32 + +#define elfhdr elf32_hdr +#define elf_phdr elf32_phdr +#define elf_note elf32_note +#define elf_shdr elf32_shdr +#define elf_sym elf32_sym +#define elf_addr_t Elf32_Off + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf32_Rela +#else +# define ELF_RELOC Elf32_Rel +#endif + +#else + +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note +#define elf_shdr elf64_shdr +#define elf_sym elf64_sym +#define elf_addr_t Elf64_Off + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf64_Rela +#else +# define ELF_RELOC Elf64_Rel +#endif + +#endif /* ELF_CLASS */ + +#ifndef ElfW +# if ELF_CLASS == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +#endif /* ELF_CLASS */ + + +#endif /* _QEMU_ELF_H */ diff --git a/qemu/qemu-git/.svn/text-base/exec-all.h.svn-base b/qemu/qemu-git/.svn/text-base/exec-all.h.svn-base new file mode 100644 index 0000000..820b59e --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/exec-all.h.svn-base @@ -0,0 +1,360 @@ +/* + * internal execution defines for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef _EXEC_ALL_H_ +#define _EXEC_ALL_H_ + +#include "qemu-common.h" + +/* allow to see translation results - the slowdown should be negligible, so we leave it */ +#define DEBUG_DISAS + +/* is_jmp field values */ +#define DISAS_NEXT 0 /* next instruction can be analyzed */ +#define DISAS_JUMP 1 /* only pc was modified dynamically */ +#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ +#define DISAS_TB_JUMP 3 /* only pc was modified statically */ + +typedef struct TranslationBlock TranslationBlock; + +/* XXX: make safe guess about sizes */ +#define MAX_OP_PER_INSTR 96 +/* A Call op needs up to 6 + 2N parameters (N = number of arguments). */ +#define MAX_OPC_PARAM 10 +#define OPC_BUF_SIZE 640 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) + +/* Maximum size a TCG op can expand to. This is complicated because a + single op may require several host instructions and register reloads. + For now take a wild guess at 192 bytes, which should allow at least + a couple of fixup instructions per argument. */ +#define TCG_MAX_OP_SIZE 192 + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) + +extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; +extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; +extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; +extern target_ulong gen_opc_jump_pc[2]; +extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + +#include "qemu-log.h" + +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); +void gen_pc_load(CPUState *env, struct TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc); + +unsigned long code_gen_max_block_size(void); +void cpu_gen_init(void); +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, + int *gen_code_size_ptr); +int cpu_restore_state(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc); +int cpu_restore_state_copy(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc); +void cpu_resume_from_signal(CPUState *env1, void *puc); +void cpu_io_recompile(CPUState *env, void *retaddr); +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, int flags, + int cflags); +void cpu_exec_init(CPUState *env); +void QEMU_NORETURN cpu_loop_exit(void); +int page_unprotect(target_ulong address, unsigned long pc, void *puc); +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, + int is_cpu_write_access); +void tb_invalidate_page_range(target_ulong start, target_ulong end); +void tlb_flush_page(CPUState *env, target_ulong addr); +void tlb_flush(CPUState *env, int flush_global); +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu); +static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + if (prot & PAGE_READ) + prot |= PAGE_EXEC; + return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); +} + +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +#define CODE_GEN_PHYS_HASH_BITS 15 +#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) + +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) + +/* estimated block size for TB allocation */ +/* XXX: use a per code average code fragment size and modulate it + according to the host CPU */ +#if defined(CONFIG_SOFTMMU) +#define CODE_GEN_AVG_BLOCK_SIZE 128 +#else +#define CODE_GEN_AVG_BLOCK_SIZE 64 +#endif + +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) +#define USE_DIRECT_JUMP +#endif + +struct TranslationBlock { + target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ + target_ulong cs_base; /* CS base for this block */ + uint64_t flags; /* flags defining in which context the code was generated */ + uint16_t size; /* size of target code for this block (1 <= + size <= TARGET_PAGE_SIZE) */ + uint16_t cflags; /* compile flags */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ + + uint8_t *tc_ptr; /* pointer to the translated code */ + /* next matching tb for physical address. */ + struct TranslationBlock *phys_hash_next; + /* first and second physical page containing code. The lower bit + of the pointer tells the index in page_next[] */ + struct TranslationBlock *page_next[2]; + target_ulong page_addr[2]; + + /* the following data are used to directly call another TB from + the code of this one. */ + uint16_t tb_next_offset[2]; /* offset of original jump target */ +#ifdef USE_DIRECT_JUMP + uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ +#else + unsigned long tb_next[2]; /* address of jump generated code */ +#endif + /* list of TBs jumping to this one. This is a circular list using + the two least significant bits of the pointers to tell what is + the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = + jmp_first */ + struct TranslationBlock *jmp_next[2]; + struct TranslationBlock *jmp_first; + uint32_t icount; +}; + +static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; +} + +static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) + | (tmp & TB_JMP_ADDR_MASK)); +} + +static inline unsigned int tb_phys_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); +} + +TranslationBlock *tb_alloc(target_ulong pc); +void tb_free(TranslationBlock *tb); +void tb_flush(CPUState *env); +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2); +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); + +extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; +extern uint8_t *code_gen_ptr; +extern int code_gen_max_blocks; + +#if defined(USE_DIRECT_JUMP) + +#if defined(_ARCH_PPC) +extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); +#define tb_set_jmp_target1 ppc_tb_set_jmp_target +#elif defined(__i386__) || defined(__x86_64__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + /* patch the branch destination */ + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + /* no need to flush icache explicitly */ +} +#elif defined(__arm__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ +#if QEMU_GNUC_PREREQ(4, 1) + void __clear_cache(char *beg, char *end); +#else + register unsigned long _beg __asm ("a1"); + register unsigned long _end __asm ("a2"); + register unsigned long _flg __asm ("a3"); +#endif + + /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ + *(uint32_t *)jmp_addr = + (*(uint32_t *)jmp_addr & ~0xffffff) + | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); + +#if QEMU_GNUC_PREREQ(4, 1) + __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); +#else + /* flush icache */ + _beg = jmp_addr; + _end = jmp_addr + 4; + _flg = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +#endif +} +#endif + +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + unsigned long offset; + + offset = tb->tb_jmp_offset[n]; + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); + offset = tb->tb_jmp_offset[n + 2]; + if (offset != 0xffff) + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); +} + +#else + +/* set the jump target */ +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + tb->tb_next[n] = addr; +} + +#endif + +static inline void tb_add_jump(TranslationBlock *tb, int n, + TranslationBlock *tb_next) +{ + /* NOTE: this test is only needed for thread safety */ + if (!tb->jmp_next[n]) { + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_next[n] = tb_next->jmp_first; + tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); + } +} + +TranslationBlock *tb_find_pc(unsigned long pc_ptr); + +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; + +#include "qemu-lock.h" + +extern spinlock_t tb_lock; + +extern int tb_invalidated_flag; + +#if !defined(CONFIG_USER_ONLY) + +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, + void *retaddr); + +#include "softmmu_defs.h" + +#define ACCESS_TYPE (NB_MMU_MODES + 1) +#define MEMSUFFIX _code +#define env cpu_single_env + +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef ACCESS_TYPE +#undef MEMSUFFIX +#undef env + +#endif + +#if defined(CONFIG_USER_ONLY) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) +{ + return addr; +} +#else +/* NOTE: this function can trigger an exception */ +/* NOTE2: the returned address is not exactly the physical address: it + is the offset relative to phys_ram_base */ +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) +{ + int mmu_idx, page_index, pd; + void *p; + + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = cpu_mmu_index(env1); + if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != + (addr & TARGET_PAGE_MASK))) { + ldub_code(addr); + } + pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK; + if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { +#if defined(TARGET_SPARC) || defined(TARGET_MIPS) + do_unassigned_access(addr, 0, 1, 0, 4); +#else + cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); +#endif + } + p = (void *)(unsigned long)addr + + env1->tlb_table[mmu_idx][page_index].addend; + return qemu_ram_addr_from_host(p); +} + +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) + return 1; + + /* If not executing code then assume we are ok. */ + if (!env->current_tb) + return 1; + + return env->can_do_io != 0; +} +#endif + +typedef void (CPUDebugExcpHandler)(CPUState *env); + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); + +/* vl.c */ +extern int singlestep; + +#endif diff --git a/qemu/qemu-git/.svn/text-base/exec.c.svn-base b/qemu/qemu-git/.svn/text-base/exec.c.svn-base new file mode 100644 index 0000000..30930aa --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/exec.c.svn-base @@ -0,0 +1,3720 @@ +/* + * virtual page mapping and translated block handling + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "qemu-common.h" +#include "tcg.h" +#ifndef X49GP +#include "hw/hw.h" +#endif +#include "osdep.h" +#include "kvm.h" +#if defined(CONFIG_USER_ONLY) +#include +#endif + +//#define DEBUG_TB_INVALIDATE +//#define DEBUG_FLUSH +//#define DEBUG_TLB +//#define DEBUG_UNASSIGNED + +/* make various TB consistency checks */ +//#define DEBUG_TB_CHECK +//#define DEBUG_TLB_CHECK + +//#define DEBUG_IOPORT +//#define DEBUG_SUBPAGE + +#if !defined(CONFIG_USER_ONLY) +/* TB consistency checks only implemented for usermode emulation. */ +#undef DEBUG_TB_CHECK +#endif + +#define SMC_BITMAP_USE_THRESHOLD 10 + +#if defined(TARGET_SPARC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 41 +#elif defined(TARGET_SPARC) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#elif defined(TARGET_ALPHA) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#define TARGET_VIRT_ADDR_SPACE_BITS 42 +#elif defined(TARGET_PPC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_X86_64) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_I386) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#else +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#endif + +static TranslationBlock *tbs; +int code_gen_max_blocks; +TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; +static int nb_tbs; +/* any access to the tbs or the page table must use this lock */ +spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; + +#if defined(__arm__) || defined(__sparc_v9__) +/* The prologue must be reachable with a direct jump. ARM and Sparc64 + have limited branch ranges (possibly also PPC) so place it in a + section close to code segment. */ +#define code_gen_section \ + __attribute__((__section__(".gen_code"))) \ + __attribute__((aligned (32))) +#elif defined(_WIN32) +/* Maximum alignment for Win32 is 16. */ +#define code_gen_section \ + __attribute__((aligned (16))) +#else +#define code_gen_section \ + __attribute__((aligned (32))) +#endif + +uint8_t code_gen_prologue[1024] code_gen_section; +static uint8_t *code_gen_buffer; +static unsigned long code_gen_buffer_size; +/* threshold to flush the translated code buffer */ +static unsigned long code_gen_buffer_max_size; +uint8_t *code_gen_ptr; + +#if !defined(CONFIG_USER_ONLY) +int phys_ram_fd; +uint8_t *phys_ram_dirty; +static int in_migration; + +typedef struct RAMBlock { + uint8_t *host; + ram_addr_t offset; + ram_addr_t length; + struct RAMBlock *next; +} RAMBlock; + +static RAMBlock *ram_blocks; +/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug) + then we can no longer assume contiguous ram offsets, and external uses + of this variable will break. */ +ram_addr_t last_ram_offset; +#endif + +CPUState *first_cpu; +/* current CPU in the current thread. It is only valid inside + cpu_exec() */ +CPUState *cpu_single_env; +/* 0 = Do not count executed instructions. + 1 = Precise instruction counting. + 2 = Adaptive rate instruction counting. */ +int use_icount = 0; +/* Current instruction counter. While executing translated code this may + include some instructions that have not yet been executed. */ +int64_t qemu_icount; + +typedef struct PageDesc { + /* list of TBs intersecting this ram page */ + TranslationBlock *first_tb; + /* in order to optimize self modifying code, we count the number + of lookups we do to a given page to use a bitmap */ + unsigned int code_write_count; + uint8_t *code_bitmap; +#if defined(CONFIG_USER_ONLY) + unsigned long flags; +#endif +} PageDesc; + +typedef struct PhysPageDesc { + /* offset in host memory of the page + io_index in the low bits */ + ram_addr_t phys_offset; + ram_addr_t region_offset; +} PhysPageDesc; + +#define L2_BITS 10 +#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS) +/* XXX: this is a temporary hack for alpha target. + * In the future, this is to be replaced by a multi-level table + * to actually be able to handle the complete 64 bits address space. + */ +#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS) +#else +#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) +#endif + +#define L1_SIZE (1 << L1_BITS) +#define L2_SIZE (1 << L2_BITS) + +unsigned long qemu_real_host_page_size; +unsigned long qemu_host_page_bits; +unsigned long qemu_host_page_size; +unsigned long qemu_host_page_mask; + +/* XXX: for system emulation, it could just be an array */ +static PageDesc *l1_map[L1_SIZE]; +static PhysPageDesc **l1_phys_map; + +#if !defined(CONFIG_USER_ONLY) +static void io_mem_init(void); + +/* io memory support */ +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +void *io_mem_opaque[IO_MEM_NB_ENTRIES]; +static char io_mem_used[IO_MEM_NB_ENTRIES]; +static int io_mem_watch; +#endif + +/* log support */ +#ifdef WIN32 +static const char *logfilename = "qemu.log"; +#else +static const char *logfilename = "/tmp/qemu.log"; +#endif +FILE *logfile; +int loglevel; +static int log_append = 0; + +/* statistics */ +static int tlb_flush_count; +static int tb_flush_count; +static int tb_phys_invalidate_count; + +#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) +typedef struct subpage_t { + target_phys_addr_t base; + CPUReadMemoryFunc * const *mem_read[TARGET_PAGE_SIZE][4]; + CPUWriteMemoryFunc * const *mem_write[TARGET_PAGE_SIZE][4]; + void *opaque[TARGET_PAGE_SIZE][2][4]; + ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4]; +} subpage_t; + +#ifdef _WIN32 +static void map_exec(void *addr, long size) +{ + DWORD old_protect; + VirtualProtect(addr, size, + PAGE_EXECUTE_READWRITE, &old_protect); + +} +#else +static void map_exec(void *addr, long size) +{ + unsigned long start, end, page_size; + + page_size = getpagesize(); + start = (unsigned long)addr; + start &= ~(page_size - 1); + + end = (unsigned long)addr + size; + end += page_size - 1; + end &= ~(page_size - 1); + + mprotect((void *)start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC); +} +#endif + +static void page_init(void) +{ + /* NOTE: we can always suppose that qemu_host_page_size >= + TARGET_PAGE_SIZE */ +#ifdef _WIN32 + { + SYSTEM_INFO system_info; + + GetSystemInfo(&system_info); + qemu_real_host_page_size = system_info.dwPageSize; + } +#else + qemu_real_host_page_size = getpagesize(); +#endif + if (qemu_host_page_size == 0) + qemu_host_page_size = qemu_real_host_page_size; + if (qemu_host_page_size < TARGET_PAGE_SIZE) + qemu_host_page_size = TARGET_PAGE_SIZE; + qemu_host_page_bits = 0; + while ((1 << qemu_host_page_bits) < qemu_host_page_size) + qemu_host_page_bits++; + qemu_host_page_mask = ~(qemu_host_page_size - 1); + l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); + memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); + +#if !defined(_WIN32) && defined(CONFIG_USER_ONLY) + { + long long startaddr, endaddr; + FILE *f; + int n; + + mmap_lock(); + last_brk = (unsigned long)sbrk(0); + f = fopen("/proc/self/maps", "r"); + if (f) { + do { + n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr); + if (n == 2) { + startaddr = MIN(startaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + endaddr = MIN(endaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + page_set_flags(startaddr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(endaddr), + PAGE_RESERVED); + } + } while (!feof(f)); + fclose(f); + } + mmap_unlock(); + } +#endif +} + +static inline PageDesc **page_l1_map(target_ulong index) +{ +#if TARGET_LONG_BITS > 32 + /* Host memory outside guest VM. For 32-bit targets we have already + excluded high addresses. */ + if (index > ((target_ulong)L2_SIZE * L1_SIZE)) + return NULL; +#endif + return &l1_map[index >> L2_BITS]; +} + +static inline PageDesc *page_find_alloc(target_ulong index) +{ + PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; + + p = *lp; + if (!p) { + /* allocate if not found */ +#if defined(CONFIG_USER_ONLY) + size_t len = sizeof(PageDesc) * L2_SIZE; + /* Don't use qemu_malloc because it may recurse. */ + p = mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + *lp = p; + if (h2g_valid(p)) { + unsigned long addr = h2g(p); + page_set_flags(addr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(addr + len), + PAGE_RESERVED); + } +#else + p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE); + *lp = p; +#endif + } + return p + (index & (L2_SIZE - 1)); +} + +static inline PageDesc *page_find(target_ulong index) +{ + PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; + + p = *lp; + if (!p) { + return NULL; + } + return p + (index & (L2_SIZE - 1)); +} + +static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc) +{ + void **lp, **p; + PhysPageDesc *pd; + + p = (void **)l1_phys_map; +#if TARGET_PHYS_ADDR_SPACE_BITS > 32 + +#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS) +#error unsupported TARGET_PHYS_ADDR_SPACE_BITS +#endif + lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1)); + p = *lp; + if (!p) { + /* allocate if not found */ + if (!alloc) + return NULL; + p = qemu_vmalloc(sizeof(void *) * L1_SIZE); + memset(p, 0, sizeof(void *) * L1_SIZE); + *lp = p; + } +#endif + lp = p + ((index >> L2_BITS) & (L1_SIZE - 1)); + pd = *lp; + if (!pd) { + int i; + /* allocate if not found */ + if (!alloc) + return NULL; + pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); + *lp = pd; + for (i = 0; i < L2_SIZE; i++) { + pd[i].phys_offset = IO_MEM_UNASSIGNED; + pd[i].region_offset = (index + i) << TARGET_PAGE_BITS; + } + } + return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1)); +} + +static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) +{ + return phys_page_find_alloc(index, 0); +} + +#if !defined(CONFIG_USER_ONLY) +static void tlb_protect_code(ram_addr_t ram_addr); +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr); +#define mmap_lock() do { } while(0) +#define mmap_unlock() do { } while(0) +#endif + +#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024) + +#if defined(CONFIG_USER_ONLY) +/* Currently it is not recommended to allocate big chunks of data in + user mode. It will change when a dedicated libc will be used */ +#define USE_STATIC_CODE_GEN_BUFFER +#endif + +#ifdef USE_STATIC_CODE_GEN_BUFFER +static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]; +#endif + +static void code_gen_alloc(unsigned long tb_size) +{ +#ifdef USE_STATIC_CODE_GEN_BUFFER + code_gen_buffer = static_code_gen_buffer; + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + map_exec(code_gen_buffer, code_gen_buffer_size); +#else + code_gen_buffer_size = tb_size; + if (code_gen_buffer_size == 0) { +#if defined(CONFIG_USER_ONLY) + /* in user mode, phys_ram_size is not meaningful */ + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; +#else + /* XXX: needs adjustments */ + code_gen_buffer_size = (unsigned long)(ram_size / 4); +#endif + } + if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) + code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; + /* The code gen buffer location may have constraints depending on + the host cpu and OS */ +#if defined(__linux__) + { + int flags; + void *start = NULL; + + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + flags |= MAP_32BIT; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#elif defined(__sparc_v9__) + // Map the buffer below 2G, so we can use direct calls and branches + flags |= MAP_FIXED; + start = (void *) 0x60000000UL; + if (code_gen_buffer_size > (512 * 1024 * 1024)) + code_gen_buffer_size = (512 * 1024 * 1024); +#elif defined(__arm__) + /* Map the buffer below 32M, so we can use direct calls and branches */ + flags |= MAP_FIXED; + start = (void *) 0x01000000UL; + if (code_gen_buffer_size > 16 * 1024 * 1024) + code_gen_buffer_size = 16 * 1024 * 1024; +#endif + code_gen_buffer = mmap(start, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + { + int flags; + void *addr = NULL; + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume + * 0x40000000 is free */ + flags |= MAP_FIXED; + addr = (void *)0x40000000; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#endif + code_gen_buffer = mmap(addr, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#else + code_gen_buffer = qemu_malloc(code_gen_buffer_size); + map_exec(code_gen_buffer, code_gen_buffer_size); +#endif +#endif /* !USE_STATIC_CODE_GEN_BUFFER */ + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); + code_gen_buffer_max_size = code_gen_buffer_size - + code_gen_max_block_size(); + code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; + tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); +} + +/* Must be called before using the QEMU cpus. 'tb_size' is the size + (in bytes) allocated to the translation buffer. Zero means default + size. */ +void cpu_exec_init_all(unsigned long tb_size) +{ + cpu_gen_init(); + code_gen_alloc(tb_size); + code_gen_ptr = code_gen_buffer; + page_init(); +#if !defined(CONFIG_USER_ONLY) + io_mem_init(); +#endif +} + +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + +static void cpu_common_pre_save(void *opaque) +{ + CPUState *env = opaque; + + cpu_synchronize_state(env); +} + +static int cpu_common_pre_load(void *opaque) +{ + CPUState *env = opaque; + + cpu_synchronize_state(env); + return 0; +} + +static int cpu_common_post_load(void *opaque, int version_id) +{ + CPUState *env = opaque; + + /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the + version_id is increased. */ + env->interrupt_request &= ~0x01; + tlb_flush(env, 1); + + return 0; +} + +static const VMStateDescription vmstate_cpu_common = { + .name = "cpu_common", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = cpu_common_pre_save, + .pre_load = cpu_common_pre_load, + .post_load = cpu_common_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(halted, CPUState), + VMSTATE_UINT32(interrupt_request, CPUState), + VMSTATE_END_OF_LIST() + } +}; +#endif + +CPUState *qemu_get_cpu(int cpu) +{ + CPUState *env = first_cpu; + + while (env) { + if (env->cpu_index == cpu) + break; + env = env->next_cpu; + } + + return env; +} + +void cpu_exec_init(CPUState *env) +{ + CPUState **penv; + int cpu_index; + +#if defined(CONFIG_USER_ONLY) + cpu_list_lock(); +#endif + env->next_cpu = NULL; + penv = &first_cpu; + cpu_index = 0; + while (*penv != NULL) { + penv = &(*penv)->next_cpu; + cpu_index++; + } + env->cpu_index = cpu_index; + env->numa_node = 0; + QTAILQ_INIT(&env->breakpoints); + QTAILQ_INIT(&env->watchpoints); + *penv = env; +#if defined(CONFIG_USER_ONLY) + cpu_list_unlock(); +#endif +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + vmstate_register(cpu_index, &vmstate_cpu_common, env); + register_savevm("cpu", cpu_index, CPU_SAVE_VERSION, + cpu_save, cpu_load, env); +#endif +} + +static inline void invalidate_page_bitmap(PageDesc *p) +{ + if (p->code_bitmap) { + qemu_free(p->code_bitmap); + p->code_bitmap = NULL; + } + p->code_write_count = 0; +} + +/* set to NULL all the 'first_tb' fields in all PageDescs */ +static void page_flush_tb(void) +{ + int i, j; + PageDesc *p; + + for(i = 0; i < L1_SIZE; i++) { + p = l1_map[i]; + if (p) { + for(j = 0; j < L2_SIZE; j++) { + p->first_tb = NULL; + invalidate_page_bitmap(p); + p++; + } + } + } +} + +/* flush all the translation blocks */ +/* XXX: tb_flush is currently not thread safe */ +void tb_flush(CPUState *env1) +{ + CPUState *env; +#if defined(DEBUG_FLUSH) + printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", + (unsigned long)(code_gen_ptr - code_gen_buffer), + nb_tbs, nb_tbs > 0 ? + ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); +#endif + if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size) + cpu_abort(env1, "Internal error: code buffer overflow\n"); + + nb_tbs = 0; + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + } + + memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); + page_flush_tb(); + + code_gen_ptr = code_gen_buffer; + /* XXX: flush processor icache at this point if cache flush is + expensive */ + tb_flush_count++; +} + +#ifdef DEBUG_TB_CHECK + +static void tb_invalidate_check(target_ulong address) +{ + TranslationBlock *tb; + int i; + address &= TARGET_PAGE_MASK; + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + if (!(address + TARGET_PAGE_SIZE <= tb->pc || + address >= tb->pc + tb->size)) { + printf("ERROR invalidate: address=" TARGET_FMT_lx + " PC=%08lx size=%04x\n", + address, (long)tb->pc, tb->size); + } + } + } +} + +/* verify that all the pages have correct rights for code */ +static void tb_page_check(void) +{ + TranslationBlock *tb; + int i, flags1, flags2; + + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + flags1 = page_get_flags(tb->pc); + flags2 = page_get_flags(tb->pc + tb->size - 1); + if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { + printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", + (long)tb->pc, tb->size, flags1, flags2); + } + } + } +} + +#endif + +/* invalidate one TB */ +static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, + int next_offset) +{ + TranslationBlock *tb1; + for(;;) { + tb1 = *ptb; + if (tb1 == tb) { + *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); + break; + } + ptb = (TranslationBlock **)((char *)tb1 + next_offset); + } +} + +static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) +{ + TranslationBlock *tb1; + unsigned int n1; + + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (tb1 == tb) { + *ptb = tb1->page_next[n1]; + break; + } + ptb = &tb1->page_next[n1]; + } +} + +static inline void tb_jmp_remove(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, **ptb; + unsigned int n1; + + ptb = &tb->jmp_next[n]; + tb1 = *ptb; + if (tb1) { + /* find tb(n) in circular list */ + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + if (n1 == 2) { + ptb = &tb1->jmp_first; + } else { + ptb = &tb1->jmp_next[n1]; + } + } + /* now we can suppress tb(n) from the list */ + *ptb = tb->jmp_next[n]; + + tb->jmp_next[n] = NULL; + } +} + +/* reset the jump entry 'n' of a TB so that it is not chained to + another TB */ +static inline void tb_reset_jump(TranslationBlock *tb, int n) +{ + tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); +} + +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) +{ + CPUState *env; + PageDesc *p; + unsigned int h, n1; + target_phys_addr_t phys_pc; + TranslationBlock *tb1, *tb2; + + /* remove the TB from the hash list */ + phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + h = tb_phys_hash_func(phys_pc); + tb_remove(&tb_phys_hash[h], tb, + offsetof(TranslationBlock, phys_hash_next)); + + /* remove the TB from the page list */ + if (tb->page_addr[0] != page_addr) { + p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { + p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + + tb_invalidated_flag = 1; + + /* remove the TB from the hash list */ + h = tb_jmp_cache_hash_func(tb->pc); + for(env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->tb_jmp_cache[h] == tb) + env->tb_jmp_cache[h] = NULL; + } + + /* suppress this TB from the two jump lists */ + tb_jmp_remove(tb, 0); + tb_jmp_remove(tb, 1); + + /* suppress any remaining jumps to this TB */ + tb1 = tb->jmp_first; + for(;;) { + n1 = (long)tb1 & 3; + if (n1 == 2) + break; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + tb2 = tb1->jmp_next[n1]; + tb_reset_jump(tb1, n1); + tb1->jmp_next[n1] = NULL; + tb1 = tb2; + } + tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ + + tb_phys_invalidate_count++; +} + +static inline void set_bits(uint8_t *tab, int start, int len) +{ + int end, mask, end1; + + end = start + len; + tab += start >> 3; + mask = 0xff << (start & 7); + if ((start & ~7) == (end & ~7)) { + if (start < end) { + mask &= ~(0xff << (end & 7)); + *tab |= mask; + } + } else { + *tab++ |= mask; + start = (start + 8) & ~7; + end1 = end & ~7; + while (start < end1) { + *tab++ = 0xff; + start += 8; + } + if (start < end) { + mask = ~(0xff << (end & 7)); + *tab |= mask; + } + } +} + +static void build_page_bitmap(PageDesc *p) +{ + int n, tb_start, tb_end; + TranslationBlock *tb; + + p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8); + + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->pc & ~TARGET_PAGE_MASK; + tb_end = tb_start + tb->size; + if (tb_end > TARGET_PAGE_SIZE) + tb_end = TARGET_PAGE_SIZE; + } else { + tb_start = 0; + tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + set_bits(p->code_bitmap, tb_start, tb_end - tb_start); + tb = tb->page_next[n]; + } +} + +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, + int flags, int cflags) +{ + TranslationBlock *tb; + uint8_t *tc_ptr; + target_ulong phys_pc, phys_page2, virt_page2; + int code_gen_size; + + phys_pc = get_phys_addr_code(env, pc); + tb = tb_alloc(pc); + if (!tb) { + /* flush must be done */ + tb_flush(env); + /* cannot fail at this point */ + tb = tb_alloc(pc); + /* Don't forget to invalidate previous TB info. */ + tb_invalidated_flag = 1; + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags; + cpu_gen_code(env, tb, &code_gen_size); + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + + /* check next page if needed */ + virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; + phys_page2 = -1; + if ((pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_phys_addr_code(env, virt_page2); + } + tb_link_phys(tb, phys_pc, phys_page2); + return tb; +} + +/* invalidate all TBs which intersect with the target physical page + starting in range [start;end[. NOTE: start and end must refer to + the same physical page. 'is_cpu_write_access' should be true if called + from a real cpu write access: the virtual CPU will exit the current + TB if code is modified inside this TB. */ +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, + int is_cpu_write_access) +{ + TranslationBlock *tb, *tb_next, *saved_tb; + CPUState *env = cpu_single_env; + target_ulong tb_start, tb_end; + PageDesc *p; + int n; +#ifdef TARGET_HAS_PRECISE_SMC + int current_tb_not_found = is_cpu_write_access; + TranslationBlock *current_tb = NULL; + int current_tb_modified = 0; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; +#endif /* TARGET_HAS_PRECISE_SMC */ + + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (!p->code_bitmap && + ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && + is_cpu_write_access) { + /* build code bitmap */ + build_page_bitmap(p); + } + + /* we remove all the TBs in the range [start, end[ */ + /* XXX: see if in some cases it could be faster to invalidate all the code */ + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + tb_next = tb->page_next[n]; + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + tb_end = tb_start + tb->size; + } else { + tb_start = tb->page_addr[1]; + tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + if (!(tb_end <= start || tb_start >= end)) { +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_not_found) { + current_tb_not_found = 0; + current_tb = NULL; + if (env->mem_io_pc) { + /* now we have a real cpu fault */ + current_tb = tb_find_pc(env->mem_io_pc); + } + } + if (current_tb == tb && + (current_tb->cflags & CF_COUNT_MASK) != 1) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, + env->mem_io_pc, NULL); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } +#endif /* TARGET_HAS_PRECISE_SMC */ + /* we need to do that to handle the case where a signal + occurs while doing tb_phys_invalidate() */ + saved_tb = NULL; + if (env) { + saved_tb = env->current_tb; + env->current_tb = NULL; + } + tb_phys_invalidate(tb, -1); + if (env) { + env->current_tb = saved_tb; + if (env->interrupt_request && env->current_tb) + cpu_interrupt(env, env->interrupt_request); + } + } + tb = tb_next; + } +#if !defined(CONFIG_USER_ONLY) + /* if no code remaining, no need to continue to use slow writes */ + if (!p->first_tb) { + invalidate_page_bitmap(p); + if (is_cpu_write_access) { + tlb_unprotect_code_phys(env, start, env->mem_io_vaddr); + } + } +#endif +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + env->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, NULL); + } +#endif +} + +/* len must be <= 8 and start must be a multiple of len */ +static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len) +{ + PageDesc *p; + int offset, b; +#if 0 + if (1) { + qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n", + cpu_single_env->mem_io_vaddr, len, + cpu_single_env->eip, + cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); + } +#endif + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (p->code_bitmap) { + offset = start & ~TARGET_PAGE_MASK; + b = p->code_bitmap[offset >> 3] >> (offset & 7); + if (b & ((1 << len) - 1)) + goto do_invalidate; + } else { + do_invalidate: + tb_invalidate_phys_page_range(start, start + len, 1); + } +} + +#if !defined(CONFIG_SOFTMMU) +static void tb_invalidate_phys_page(target_phys_addr_t addr, + unsigned long pc, void *puc) +{ + TranslationBlock *tb; + PageDesc *p; + int n; +#ifdef TARGET_HAS_PRECISE_SMC + TranslationBlock *current_tb = NULL; + CPUState *env = cpu_single_env; + int current_tb_modified = 0; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; +#endif + + addr &= TARGET_PAGE_MASK; + p = page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return; + tb = p->first_tb; +#ifdef TARGET_HAS_PRECISE_SMC + if (tb && pc != 0) { + current_tb = tb_find_pc(pc); + } +#endif + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb == tb && + (current_tb->cflags & CF_COUNT_MASK) != 1) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, pc, puc); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } +#endif /* TARGET_HAS_PRECISE_SMC */ + tb_phys_invalidate(tb, addr); + tb = tb->page_next[n]; + } + p->first_tb = NULL; +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + env->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, puc); + } +#endif +} +#endif + +/* add the tb in the target page and protect it if necessary */ +static inline void tb_alloc_page(TranslationBlock *tb, + unsigned int n, target_ulong page_addr) +{ + PageDesc *p; + TranslationBlock *last_first_tb; + + tb->page_addr[n] = page_addr; + p = page_find_alloc(page_addr >> TARGET_PAGE_BITS); + tb->page_next[n] = p->first_tb; + last_first_tb = p->first_tb; + p->first_tb = (TranslationBlock *)((long)tb | n); + invalidate_page_bitmap(p); + +#if defined(TARGET_HAS_SMC) || 1 + +#if defined(CONFIG_USER_ONLY) + if (p->flags & PAGE_WRITE) { + target_ulong addr; + PageDesc *p2; + int prot; + + /* force the host page as non writable (writes will have a + page fault + mprotect overhead) */ + page_addr &= qemu_host_page_mask; + prot = 0; + for(addr = page_addr; addr < page_addr + qemu_host_page_size; + addr += TARGET_PAGE_SIZE) { + + p2 = page_find (addr >> TARGET_PAGE_BITS); + if (!p2) + continue; + prot |= p2->flags; + p2->flags &= ~PAGE_WRITE; + page_get_flags(addr); + } + mprotect(g2h(page_addr), qemu_host_page_size, + (prot & PAGE_BITS) & ~PAGE_WRITE); +#ifdef DEBUG_TB_INVALIDATE + printf("protecting code page: 0x" TARGET_FMT_lx "\n", + page_addr); +#endif + } +#else + /* if some code is already present, then the pages are already + protected. So we handle the case where only the first TB is + allocated in a physical page */ + if (!last_first_tb) { + tlb_protect_code(page_addr); + } +#endif + +#endif /* TARGET_HAS_SMC */ +} + +/* Allocate a new translation block. Flush the translation buffer if + too many translation blocks or too much generated code. */ +TranslationBlock *tb_alloc(target_ulong pc) +{ + TranslationBlock *tb; + + if (nb_tbs >= code_gen_max_blocks || + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) + return NULL; + tb = &tbs[nb_tbs++]; + tb->pc = pc; + tb->cflags = 0; + return tb; +} + +void tb_free(TranslationBlock *tb) +{ + /* In practice this is mostly used for single use temporary TB + Ignore the hard cases and just back up if this TB happens to + be the last one generated. */ + if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { + code_gen_ptr = tb->tc_ptr; + nb_tbs--; + } +} + +/* add a new TB and link it to the physical page tables. phys_page2 is + (-1) to indicate that only one page contains the TB. */ +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2) +{ + unsigned int h; + TranslationBlock **ptb; + + /* Grab the mmap lock to stop another thread invalidating this TB + before we are done. */ + mmap_lock(); + /* add in the physical hash table */ + h = tb_phys_hash_func(phys_pc); + ptb = &tb_phys_hash[h]; + tb->phys_hash_next = *ptb; + *ptb = tb; + + /* add in the page list */ + tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK); + if (phys_page2 != -1) + tb_alloc_page(tb, 1, phys_page2); + else + tb->page_addr[1] = -1; + + tb->jmp_first = (TranslationBlock *)((long)tb | 2); + tb->jmp_next[0] = NULL; + tb->jmp_next[1] = NULL; + + /* init original jump addresses */ + if (tb->tb_next_offset[0] != 0xffff) + tb_reset_jump(tb, 0); + if (tb->tb_next_offset[1] != 0xffff) + tb_reset_jump(tb, 1); + +#ifdef DEBUG_TB_CHECK + tb_page_check(); +#endif + mmap_unlock(); +} + +/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < + tb[1].tc_ptr. Return NULL if not found */ +TranslationBlock *tb_find_pc(unsigned long tc_ptr) +{ + int m_min, m_max, m; + unsigned long v; + TranslationBlock *tb; + + if (nb_tbs <= 0) + return NULL; + if (tc_ptr < (unsigned long)code_gen_buffer || + tc_ptr >= (unsigned long)code_gen_ptr) + return NULL; + /* binary search (cf Knuth) */ + m_min = 0; + m_max = nb_tbs - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + tb = &tbs[m]; + v = (unsigned long)tb->tc_ptr; + if (v == tc_ptr) + return tb; + else if (tc_ptr < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return &tbs[m_max]; +} + +static void tb_reset_jump_recursive(TranslationBlock *tb); + +static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, *tb_next, **ptb; + unsigned int n1; + + tb1 = tb->jmp_next[n]; + if (tb1 != NULL) { + /* find head of list */ + for(;;) { + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == 2) + break; + tb1 = tb1->jmp_next[n1]; + } + /* we are now sure now that tb jumps to tb1 */ + tb_next = tb1; + + /* remove tb from the jmp_first list */ + ptb = &tb_next->jmp_first; + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + ptb = &tb1->jmp_next[n1]; + } + *ptb = tb->jmp_next[n]; + tb->jmp_next[n] = NULL; + + /* suppress the jump to next tb in generated code */ + tb_reset_jump(tb, n); + + /* suppress jumps in the tb on which we could have jumped */ + tb_reset_jump_recursive(tb_next); + } +} + +static void tb_reset_jump_recursive(TranslationBlock *tb) +{ + tb_reset_jump_recursive2(tb, 0); + tb_reset_jump_recursive2(tb, 1); +} + +#if defined(TARGET_HAS_ICE) +static void breakpoint_invalidate(CPUState *env, target_ulong pc) +{ + target_phys_addr_t addr; + target_ulong pd; + ram_addr_t ram_addr; + PhysPageDesc *p; + + addr = cpu_get_phys_page_debug(env, pc); + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK); + tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); +} +#endif + +/* Add a watchpoint. */ +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint) +{ + target_ulong len_mask = ~(len - 1); + CPUWatchpoint *wp; + + /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */ + if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) { + fprintf(stderr, "qemu: tried to set invalid watchpoint at " + TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len); + return -EINVAL; + } + wp = qemu_malloc(sizeof(*wp)); + + wp->vaddr = addr; + wp->len_mask = len_mask; + wp->flags = flags; + + /* keep all GDB-injected watchpoints in front */ + if (flags & BP_GDB) + QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry); + else + QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry); + + tlb_flush_page(env, addr); + + if (watchpoint) + *watchpoint = wp; + return 0; +} + +/* Remove a specific watchpoint. */ +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len, + int flags) +{ + target_ulong len_mask = ~(len - 1); + CPUWatchpoint *wp; + + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if (addr == wp->vaddr && len_mask == wp->len_mask + && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) { + cpu_watchpoint_remove_by_ref(env, wp); + return 0; + } + } + return -ENOENT; +} + +/* Remove a specific watchpoint by reference. */ +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint) +{ + QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry); + + tlb_flush_page(env, watchpoint->vaddr); + + qemu_free(watchpoint); +} + +/* Remove all matching watchpoints. */ +void cpu_watchpoint_remove_all(CPUState *env, int mask) +{ + CPUWatchpoint *wp, *next; + + QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) { + if (wp->flags & mask) + cpu_watchpoint_remove_by_ref(env, wp); + } +} + +/* Add a breakpoint. */ +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + bp = qemu_malloc(sizeof(*bp)); + + bp->pc = pc; + bp->flags = flags; + + /* keep all GDB-injected breakpoints in front */ + if (flags & BP_GDB) + QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry); + else + QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry); + + breakpoint_invalidate(env, pc); + + if (breakpoint) + *breakpoint = bp; + return 0; +#else + return -ENOSYS; +#endif +} + +/* Remove a specific breakpoint. */ +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == pc && bp->flags == flags) { + cpu_breakpoint_remove_by_ref(env, bp); + return 0; + } + } + return -ENOENT; +#else + return -ENOSYS; +#endif +} + +/* Remove a specific breakpoint by reference. */ +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint) +{ +#if defined(TARGET_HAS_ICE) + QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry); + + breakpoint_invalidate(env, breakpoint->pc); + + qemu_free(breakpoint); +#endif +} + +/* Remove all matching breakpoints. */ +void cpu_breakpoint_remove_all(CPUState *env, int mask) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp, *next; + + QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) { + if (bp->flags & mask) + cpu_breakpoint_remove_by_ref(env, bp); + } +#endif +} + +/* enable or disable single step mode. EXCP_DEBUG is returned by the + CPU loop after each instruction */ +void cpu_single_step(CPUState *env, int enabled) +{ +#if defined(TARGET_HAS_ICE) + if (env->singlestep_enabled != enabled) { + env->singlestep_enabled = enabled; + if (kvm_enabled()) + kvm_update_guest_debug(env, 0); + else { + /* must flush all the translated code to avoid inconsistencies */ + /* XXX: only flush what is necessary */ + tb_flush(env); + } + } +#endif +} + +/* enable or disable low levels log */ +void cpu_set_log(int log_flags) +{ + loglevel = log_flags; + if (loglevel && !logfile) { + logfile = fopen(logfilename, log_append ? "a" : "w"); + if (!logfile) { + perror(logfilename); + _exit(1); + } +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static char logfile_buf[4096]; + setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); + } +#elif !defined(_WIN32) + /* Win32 doesn't support line-buffering and requires size >= 2 */ + setvbuf(logfile, NULL, _IOLBF, 0); +#endif + log_append = 1; + } + if (!loglevel && logfile) { + fclose(logfile); + logfile = NULL; + } +} + +void cpu_set_log_filename(const char *filename) +{ + logfilename = strdup(filename); + if (logfile) { + fclose(logfile); + logfile = NULL; + } + cpu_set_log(loglevel); +} + +static void cpu_unlink_tb(CPUState *env) +{ + /* FIXME: TB unchaining isn't SMP safe. For now just ignore the + problem and hope the cpu will stop of its own accord. For userspace + emulation this often isn't actually as bad as it sounds. Often + signals are used primarily to interrupt blocking syscalls. */ + TranslationBlock *tb; + static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; + + tb = env->current_tb; + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + if (tb) { + spin_lock(&interrupt_lock); + env->current_tb = NULL; + tb_reset_jump_recursive(tb); + spin_unlock(&interrupt_lock); + } +} + +/* mask must never be zero, except for A20 change call */ +void cpu_interrupt(CPUState *env, int mask) +{ + int old_mask; + + old_mask = env->interrupt_request; + env->interrupt_request |= mask; + +#ifndef CONFIG_USER_ONLY + /* + * If called from iothread context, wake the target cpu in + * case its halted. + */ + if (!qemu_cpu_self(env)) { + qemu_cpu_kick(env); + return; + } +#endif + + if (use_icount) { + env->icount_decr.u16.high = 0xffff; +#ifndef CONFIG_USER_ONLY + if (!can_do_io(env) + && (mask & ~old_mask) != 0) { + cpu_abort(env, "Raised interrupt while not in I/O function"); + } +#endif + } else { + cpu_unlink_tb(env); + } +} + +void cpu_reset_interrupt(CPUState *env, int mask) +{ + env->interrupt_request &= ~mask; +} + +void cpu_exit(CPUState *env) +{ + env->exit_request = 1; + cpu_unlink_tb(env); +} + +const CPULogItem cpu_log_items[] = { + { CPU_LOG_TB_OUT_ASM, "out_asm", + "show generated host assembly code for each compiled TB" }, + { CPU_LOG_TB_IN_ASM, "in_asm", + "show target assembly code for each compiled TB" }, + { CPU_LOG_TB_OP, "op", + "show micro ops for each compiled TB" }, + { CPU_LOG_TB_OP_OPT, "op_opt", + "show micro ops " +#ifdef TARGET_I386 + "before eflags optimization and " +#endif + "after liveness analysis" }, + { CPU_LOG_INT, "int", + "show interrupts/exceptions in short format" }, + { CPU_LOG_EXEC, "exec", + "show trace before each executed TB (lots of logs)" }, + { CPU_LOG_TB_CPU, "cpu", + "show CPU state before block translation" }, +#ifdef TARGET_I386 + { CPU_LOG_PCALL, "pcall", + "show protected mode far calls/returns/exceptions" }, + { CPU_LOG_RESET, "cpu_reset", + "show CPU state before CPU resets" }, +#endif +#ifdef DEBUG_IOPORT + { CPU_LOG_IOPORT, "ioport", + "show all i/o ports accesses" }, +#endif + { 0, NULL, NULL }, +}; + +static int cmp1(const char *s1, int n, const char *s2) +{ + if (strlen(s2) != n) + return 0; + return memcmp(s1, s2, n) == 0; +} + +/* takes a comma separated list of log masks. Return 0 if error. */ +int cpu_str_to_log_mask(const char *str) +{ + const CPULogItem *item; + int mask; + const char *p, *p1; + + p = str; + mask = 0; + for(;;) { + p1 = strchr(p, ','); + if (!p1) + p1 = p + strlen(p); + if(cmp1(p,p1-p,"all")) { + for(item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { + for(item = cpu_log_items; item->mask != 0; item++) { + if (cmp1(p, p1 - p, item->name)) + goto found; + } + return 0; + } + found: + mask |= item->mask; + if (*p1 != ',') + break; + p = p1 + 1; + } + return mask; +} + +void cpu_abort(CPUState *env, const char *fmt, ...) +{ + va_list ap; + va_list ap2; + + va_start(ap, fmt); + va_copy(ap2, ap); + fprintf(stderr, "qemu: fatal: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +#ifdef TARGET_I386 + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(env, stderr, fprintf, 0); +#endif + if (qemu_log_enabled()) { + qemu_log("qemu: fatal: "); + qemu_log_vprintf(fmt, ap2); + qemu_log("\n"); +#ifdef TARGET_I386 + log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + log_cpu_state(env, 0); +#endif + qemu_log_flush(); + qemu_log_close(); + } + va_end(ap2); + va_end(ap); + abort(); +} + +CPUState *cpu_copy(CPUState *env) +{ + CPUState *new_env = cpu_init(env->cpu_model_str); + CPUState *next_cpu = new_env->next_cpu; + int cpu_index = new_env->cpu_index; +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + CPUWatchpoint *wp; +#endif + + memcpy(new_env, env, sizeof(CPUState)); + + /* Preserve chaining and index. */ + new_env->next_cpu = next_cpu; + new_env->cpu_index = cpu_index; + + /* Clone all break/watchpoints. + Note: Once we support ptrace with hw-debug register access, make sure + BP_CPU break/watchpoints are handled correctly on clone. */ + QTAILQ_INIT(&env->breakpoints); + QTAILQ_INIT(&env->watchpoints); +#if defined(TARGET_HAS_ICE) + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL); + } + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1, + wp->flags, NULL); + } +#endif + + return new_env; +} + +#if !defined(CONFIG_USER_ONLY) + +static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr) +{ + unsigned int i; + + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); + + i = tb_jmp_cache_hash_page(addr); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); +} + +static CPUTLBEntry s_cputlb_empty_entry = { + .addr_read = -1, + .addr_write = -1, + .addr_code = -1, + .addend = -1, +}; + +/* NOTE: if flush_global is true, also flush global entries (not + implemented yet) */ +void tlb_flush(CPUState *env, int flush_global) +{ + int i; + +#if defined(DEBUG_TLB) + printf("tlb_flush:\n"); +#endif + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + + for(i = 0; i < CPU_TLB_SIZE; i++) { + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + env->tlb_table[mmu_idx][i] = s_cputlb_empty_entry; + } + } + + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + + tlb_flush_count++; +} + +static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) +{ + if (addr == (tlb_entry->addr_read & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_write & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_code & + (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + *tlb_entry = s_cputlb_empty_entry; + } +} + +void tlb_flush_page(CPUState *env, target_ulong addr) +{ + int i; + int mmu_idx; + +#if defined(DEBUG_TLB) + printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); +#endif + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + + addr &= TARGET_PAGE_MASK; + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr); + + tlb_flush_jmp_cache(env, addr); +} + +/* update the TLBs so that writes to code in the virtual page 'addr' + can be detected */ +static void tlb_protect_code(ram_addr_t ram_addr) +{ + cpu_physical_memory_reset_dirty(ram_addr, + ram_addr + TARGET_PAGE_SIZE, + CODE_DIRTY_FLAG); +} + +/* update the TLB so that writes in physical page 'phys_addr' are no longer + tested for self modifying code */ +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr) +{ + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG; +} + +static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, + unsigned long start, unsigned long length) +{ + unsigned long addr; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((addr - start) < length) { + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY; + } + } +} + +/* Note: start and end must be within the same ram block. */ +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags) +{ + CPUState *env; + unsigned long length, start1; + int i, mask, len; + uint8_t *p; + + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + + length = end - start; + if (length == 0) + return; + len = length >> TARGET_PAGE_BITS; + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + for(i = 0; i < len; i++) + p[i] &= mask; + + /* we modify the TLB cache so that the dirty bit will be set again + when accessing the range */ + start1 = (unsigned long)qemu_get_ram_ptr(start); + /* Chek that we don't span multiple blocks - this breaks the + address comparisons below. */ + if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1 + != (end - 1) - start) { + abort(); + } + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i], + start1, length); + } + } +} + +int cpu_physical_memory_set_dirty_tracking(int enable) +{ + in_migration = enable; + if (kvm_enabled()) { + return kvm_set_migration_log(enable); + } + return 0; +} + +int cpu_physical_memory_get_dirty_tracking(void) +{ + return in_migration; +} + +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) +{ + int ret = 0; + + if (kvm_enabled()) + ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + return ret; +} + +static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) +{ + ram_addr_t ram_addr; + void *p; + + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK) + + tlb_entry->addend); + ram_addr = qemu_ram_addr_from_host(p); + if (!cpu_physical_memory_is_dirty(ram_addr)) { + tlb_entry->addr_write |= TLB_NOTDIRTY; + } + } +} + +/* update the TLB according to the current state of the dirty bits */ +void cpu_tlb_update_dirty(CPUState *env) +{ + int i; + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_table[mmu_idx][i]); + } +} + +static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) +{ + if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) + tlb_entry->addr_write = vaddr; +} + +/* update the TLB corresponding to virtual page vaddr + so that it is no longer dirty */ +static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr) +{ + int i; + int mmu_idx; + + vaddr &= TARGET_PAGE_MASK; + i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr); +} + +/* add a new TLB entry. At most one entry for a given virtual address + is permitted. Return 0 if OK or 2 if the page could not be mapped + (can only happen in non SOFTMMU mode for I/O pages or pages + conflicting with the host address space). */ +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + PhysPageDesc *p; + unsigned long pd; + unsigned int index; + target_ulong address; + target_ulong code_address; + target_phys_addr_t addend; + int ret; + CPUTLBEntry *te; + CPUWatchpoint *wp; + target_phys_addr_t iotlb; + + p = phys_page_find(paddr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } +#if defined(DEBUG_TLB) + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n", + vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd); +#endif + + ret = 0; + address = vaddr; + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { + /* IO memory case (romd handled later) */ + address |= TLB_MMIO; + } + addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK); + if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { + /* Normal RAM. */ + iotlb = pd & TARGET_PAGE_MASK; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM) + iotlb |= IO_MEM_NOTDIRTY; + else + iotlb |= IO_MEM_ROM; + } else { + /* IO handlers are currently passed a physical address. + It would be nice to pass an offset from the base address + of that region. This would avoid having to special case RAM, + and avoid full address decoding in every device. + We can't use the high bits of pd for this because + IO_MEM_ROMD uses these as a ram address. */ + iotlb = (pd & ~TARGET_PAGE_MASK); + if (p) { + iotlb += p->region_offset; + } else { + iotlb += paddr; + } + } + + code_address = address; + /* Make accesses to pages with watchpoints go via the + watchpoint trap routines. */ + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) { + iotlb = io_mem_watch + paddr; + /* TODO: The memory case can be optimized by not trapping + reads of pages with a write breakpoint. */ + address |= TLB_MMIO; + } + } + + index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + env->iotlb[mmu_idx][index] = iotlb - vaddr; + te = &env->tlb_table[mmu_idx][index]; + te->addend = addend - vaddr; + if (prot & PAGE_READ) { + te->addr_read = address; + } else { + te->addr_read = -1; + } + + if (prot & PAGE_EXEC) { + te->addr_code = code_address; + } else { + te->addr_code = -1; + } + if (prot & PAGE_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* Write access calls the I/O callback. */ + te->addr_write = address | TLB_MMIO; + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + !cpu_physical_memory_is_dirty(pd)) { + te->addr_write = address | TLB_NOTDIRTY; + } else { + te->addr_write = address; + } + } else { + te->addr_write = -1; + } + return ret; +} + +#else + +void tlb_flush(CPUState *env, int flush_global) +{ +} + +void tlb_flush_page(CPUState *env, target_ulong addr) +{ +} + +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + return 0; +} + +/* + * Walks guest process memory "regions" one by one + * and calls callback function 'fn' for each region. + */ +int walk_memory_regions(void *priv, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)) +{ + unsigned long start, end; + PageDesc *p = NULL; + int i, j, prot, prot1; + int rc = 0; + + start = end = -1; + prot = 0; + + for (i = 0; i <= L1_SIZE; i++) { + p = (i < L1_SIZE) ? l1_map[i] : NULL; + for (j = 0; j < L2_SIZE; j++) { + prot1 = (p == NULL) ? 0 : p[j].flags; + /* + * "region" is one continuous chunk of memory + * that has same protection flags set. + */ + if (prot1 != prot) { + end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); + if (start != -1) { + rc = (*fn)(priv, start, end, prot); + /* callback can stop iteration by returning != 0 */ + if (rc != 0) + return (rc); + } + if (prot1 != 0) + start = end; + else + start = -1; + prot = prot1; + } + if (p == NULL) + break; + } + } + return (rc); +} + +static int dump_region(void *priv, unsigned long start, + unsigned long end, unsigned long prot) +{ + FILE *f = (FILE *)priv; + + (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", + start, end, end - start, + ((prot & PAGE_READ) ? 'r' : '-'), + ((prot & PAGE_WRITE) ? 'w' : '-'), + ((prot & PAGE_EXEC) ? 'x' : '-')); + + return (0); +} + +/* dump memory mappings */ +void page_dump(FILE *f) +{ + (void) fprintf(f, "%-8s %-8s %-8s %s\n", + "start", "end", "size", "prot"); + walk_memory_regions(f, dump_region); +} + +int page_get_flags(target_ulong address) +{ + PageDesc *p; + + p = page_find(address >> TARGET_PAGE_BITS); + if (!p) + return 0; + return p->flags; +} + +/* modify the flags of a page and invalidate the code if + necessary. The flag PAGE_WRITE_ORG is positioned automatically + depending on PAGE_WRITE */ +void page_set_flags(target_ulong start, target_ulong end, int flags) +{ + PageDesc *p; + target_ulong addr; + + /* mmap_lock should already be held. */ + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + if (flags & PAGE_WRITE) + flags |= PAGE_WRITE_ORG; + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* We may be called for host regions that are outside guest + address space. */ + if (!p) + return; + /* if the write protection is set, then we invalidate the code + inside */ + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) && + p->first_tb) { + tb_invalidate_phys_page(addr, 0, NULL); + } + p->flags = flags; + } +} + +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + PageDesc *p; + target_ulong end; + target_ulong addr; + + if (start + len < start) + /* we've wrapped around */ + return -1; + + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ + start = start & TARGET_PAGE_MASK; + + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find(addr >> TARGET_PAGE_BITS); + if( !p ) + return -1; + if( !(p->flags & PAGE_VALID) ) + return -1; + + if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) + return -1; + if (flags & PAGE_WRITE) { + if (!(p->flags & PAGE_WRITE_ORG)) + return -1; + /* unprotect the page if it was put read-only because it + contains translated code */ + if (!(p->flags & PAGE_WRITE)) { + if (!page_unprotect(addr, 0, NULL)) + return -1; + } + return 0; + } + } + return 0; +} + +/* called from signal handler: invalidate the code and unprotect the + page. Return TRUE if the fault was successfully handled. */ +int page_unprotect(target_ulong address, unsigned long pc, void *puc) +{ + unsigned int page_index, prot, pindex; + PageDesc *p, *p1; + target_ulong host_start, host_end, addr; + + /* Technically this isn't safe inside a signal handler. However we + know this only ever happens in a synchronous SEGV handler, so in + practice it seems to be ok. */ + mmap_lock(); + + host_start = address & qemu_host_page_mask; + page_index = host_start >> TARGET_PAGE_BITS; + p1 = page_find(page_index); + if (!p1) { + mmap_unlock(); + return 0; + } + host_end = host_start + qemu_host_page_size; + p = p1; + prot = 0; + for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= p->flags; + p++; + } + /* if the page was really writable, then we change its + protection back to writable */ + if (prot & PAGE_WRITE_ORG) { + pindex = (address - host_start) >> TARGET_PAGE_BITS; + if (!(p1[pindex].flags & PAGE_WRITE)) { + mprotect((void *)g2h(host_start), qemu_host_page_size, + (prot & PAGE_BITS) | PAGE_WRITE); + p1[pindex].flags |= PAGE_WRITE; + /* and since the content will be modified, we must invalidate + the corresponding translated code. */ + tb_invalidate_phys_page(address, pc, puc); +#ifdef DEBUG_TB_CHECK + tb_invalidate_check(address); +#endif + mmap_unlock(); + return 1; + } + } + mmap_unlock(); + return 0; +} + +static inline void tlb_set_dirty(CPUState *env, + unsigned long addr, target_ulong vaddr) +{ +} +#endif /* defined(CONFIG_USER_ONLY) */ + +#if !defined(CONFIG_USER_ONLY) + +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + ram_addr_t memory, ram_addr_t region_offset); +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory, ram_addr_t region_offset); +#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \ + need_subpage) \ + do { \ + if (addr > start_addr) \ + start_addr2 = 0; \ + else { \ + start_addr2 = start_addr & ~TARGET_PAGE_MASK; \ + if (start_addr2 > 0) \ + need_subpage = 1; \ + } \ + \ + if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \ + end_addr2 = TARGET_PAGE_SIZE - 1; \ + else { \ + end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \ + if (end_addr2 < TARGET_PAGE_SIZE - 1) \ + need_subpage = 1; \ + } \ + } while (0) + +/* register physical memory. + For RAM, 'size' must be a multiple of the target page size. + If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an + io memory page. The address used when calling the IO function is + the offset from the start of the region, plus region_offset. Both + start_addr and region_offset are rounded down to a page boundary + before calculating this offset. This should not be a problem unless + the low bits of start_addr and region_offset differ. */ +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset, + ram_addr_t region_offset) +{ + target_phys_addr_t addr, end_addr; + PhysPageDesc *p; + CPUState *env; + ram_addr_t orig_size = size; + void *subpage; + + if (kvm_enabled()) + kvm_set_phys_mem(start_addr, size, phys_offset); + + if (phys_offset == IO_MEM_UNASSIGNED) { + region_offset = start_addr; + } + region_offset &= TARGET_PAGE_MASK; + size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; + end_addr = start_addr + (target_phys_addr_t)size; + for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (p && p->phys_offset != IO_MEM_UNASSIGNED) { + ram_addr_t orig_memory = p->phys_offset; + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, + need_subpage); + if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) { + if (!(orig_memory & IO_MEM_SUBPAGE)) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, orig_memory, + p->region_offset); + } else { + subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK) + >> IO_MEM_SHIFT]; + } + subpage_register(subpage, start_addr2, end_addr2, phys_offset, + region_offset); + p->region_offset = 0; + } else { + p->phys_offset = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) + phys_offset += TARGET_PAGE_SIZE; + } + } else { + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); + p->phys_offset = phys_offset; + p->region_offset = region_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) { + phys_offset += TARGET_PAGE_SIZE; + } else { + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, + end_addr2, need_subpage); + + if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, IO_MEM_UNASSIGNED, + addr & TARGET_PAGE_MASK); + subpage_register(subpage, start_addr2, end_addr2, + phys_offset, region_offset); + p->region_offset = 0; + } + } + } + region_offset += TARGET_PAGE_SIZE; + } + + /* since each CPU stores ram addresses in its TLB cache, we must + reset the modified entries */ + /* XXX: slow ! */ + for(env = first_cpu; env != NULL; env = env->next_cpu) { + tlb_flush(env, 1); + } +} + +/* XXX: temporary until new memory mapping API */ +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) +{ + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return IO_MEM_UNASSIGNED; + return p->phys_offset; +} + +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ + if (kvm_enabled()) + kvm_coalesce_mmio_region(addr, size); +} + +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ + if (kvm_enabled()) + kvm_uncoalesce_mmio_region(addr, size); +} + +#ifdef X49GP +ram_addr_t x49gp_ram_alloc(ram_addr_t size, uint8_t *base); +ram_addr_t x49gp_ram_alloc(ram_addr_t size, uint8_t *base) +{ + RAMBlock *new_block; + + size = TARGET_PAGE_ALIGN(size); + new_block = qemu_malloc(sizeof(*new_block)); + new_block->host = base; + new_block->offset = last_ram_offset; + new_block->length = size; + + new_block->next = ram_blocks; + ram_blocks = new_block; + + last_ram_offset += size; + + return new_block->offset; +} +#else +ram_addr_t qemu_ram_alloc(ram_addr_t size) +{ + RAMBlock *new_block; + + size = TARGET_PAGE_ALIGN(size); + new_block = qemu_malloc(sizeof(*new_block)); + +#if defined(TARGET_S390X) && defined(CONFIG_KVM) + /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */ + new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +#else + new_block->host = qemu_vmalloc(size); +#endif +#ifdef MADV_MERGEABLE + madvise(new_block->host, size, MADV_MERGEABLE); +#endif + new_block->offset = last_ram_offset; + new_block->length = size; + + new_block->next = ram_blocks; + ram_blocks = new_block; + + phys_ram_dirty = qemu_realloc(phys_ram_dirty, + (last_ram_offset + size) >> TARGET_PAGE_BITS); + memset(phys_ram_dirty + (last_ram_offset >> TARGET_PAGE_BITS), + 0xff, size >> TARGET_PAGE_BITS); + + last_ram_offset += size; + + if (kvm_enabled()) + kvm_setup_guest_memory(new_block->host, size); + + return new_block->offset; +} +#endif + +void qemu_ram_free(ram_addr_t addr) +{ + /* TODO: implement this. */ +} + +/* Return a host pointer to ram allocated with qemu_ram_alloc. + With the exception of the softmmu code in this file, this should + only be used for local memory (e.g. video ram) that the device owns, + and knows it isn't going to access beyond the end of the block. + + It should not be used for general purpose DMA. + Use cpu_physical_memory_map/cpu_physical_memory_rw instead. + */ +void *qemu_get_ram_ptr(ram_addr_t addr) +{ + RAMBlock *prev; + RAMBlock **prevp; + RAMBlock *block; + + prev = NULL; + prevp = &ram_blocks; + block = ram_blocks; + while (block && (block->offset > addr + || block->offset + block->length <= addr)) { + if (prev) + prevp = &prev->next; + prev = block; + block = block->next; + } + if (!block) { + fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); + abort(); + } + /* Move this entry to to start of the list. */ + if (prev) { + prev->next = block->next; + block->next = *prevp; + *prevp = block; + } + return block->host + (addr - block->offset); +} + +/* Some of the softmmu routines need to translate from a host pointer + (typically a TLB entry) back to a ram offset. */ +ram_addr_t qemu_ram_addr_from_host(void *ptr) +{ + RAMBlock *prev; + RAMBlock **prevp; + RAMBlock *block; + uint8_t *host = ptr; + + prev = NULL; + prevp = &ram_blocks; + block = ram_blocks; + while (block && (block->host > host + || block->host + block->length <= host)) { + if (prev) + prevp = &prev->next; + prev = block; + block = block->next; + } + if (!block) { + fprintf(stderr, "Bad ram pointer %p\n", ptr); + abort(); + } + return block->offset + (host - block->host); +} + +static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 1); +#endif + return 0; +} + +static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 2); +#endif + return 0; +} + +static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 4); +#endif + return 0; +} + +static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 1); +#endif +} + +static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 2); +#endif +} + +static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 4); +#endif +} + +static CPUReadMemoryFunc * const unassigned_mem_read[3] = { + unassigned_mem_readb, + unassigned_mem_readw, + unassigned_mem_readl, +}; + +static CPUWriteMemoryFunc * const unassigned_mem_write[3] = { + unassigned_mem_writeb, + unassigned_mem_writew, + unassigned_mem_writel, +}; + +static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 1); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stb_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 2); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stw_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 4); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stl_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static CPUReadMemoryFunc * const error_mem_read[3] = { + NULL, /* never used */ + NULL, /* never used */ + NULL, /* never used */ +}; + +static CPUWriteMemoryFunc * const notdirty_mem_write[3] = { + notdirty_mem_writeb, + notdirty_mem_writew, + notdirty_mem_writel, +}; + +/* Generate a debug exception if a watchpoint has been hit. */ +static void check_watchpoint(int offset, int len_mask, int flags) +{ + CPUState *env = cpu_single_env; + target_ulong pc, cs_base; + TranslationBlock *tb; + target_ulong vaddr; + CPUWatchpoint *wp; + int cpu_flags; + + if (env->watchpoint_hit) { + /* We re-entered the check after replacing the TB. Now raise + * the debug interrupt so that is will trigger after the + * current instruction. */ + cpu_interrupt(env, CPU_INTERRUPT_DEBUG); + return; + } + vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if ((vaddr == (wp->vaddr & len_mask) || + (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) { + wp->flags |= BP_WATCHPOINT_HIT; + if (!env->watchpoint_hit) { + env->watchpoint_hit = wp; + tb = tb_find_pc(env->mem_io_pc); + if (!tb) { + cpu_abort(env, "check_watchpoint: could not find TB for " + "pc=%p", (void *)env->mem_io_pc); + } + cpu_restore_state(tb, env, env->mem_io_pc, NULL); + tb_phys_invalidate(tb, -1); + if (wp->flags & BP_STOP_BEFORE_ACCESS) { + env->exception_index = EXCP_DEBUG; + } else { + cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags); + tb_gen_code(env, pc, cs_base, cpu_flags, 1); + } + cpu_resume_from_signal(env, NULL); + } + } else { + wp->flags &= ~BP_WATCHPOINT_HIT; + } + } +} + +/* Watchpoint access routines. Watchpoints are inserted using TLB tricks, + so these check for a hit then pass through to the normal out-of-line + phys routines. */ +static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ); + return ldub_phys(addr); +} + +static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ); + return lduw_phys(addr); +} + +static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ); + return ldl_phys(addr); +} + +static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE); + stb_phys(addr, val); +} + +static void watch_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE); + stw_phys(addr, val); +} + +static void watch_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE); + stl_phys(addr, val); +} + +static CPUReadMemoryFunc * const watch_mem_read[3] = { + watch_mem_readb, + watch_mem_readw, + watch_mem_readl, +}; + +static CPUWriteMemoryFunc * const watch_mem_write[3] = { + watch_mem_writeb, + watch_mem_writew, + watch_mem_writel, +}; + +static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr, + unsigned int len) +{ + uint32_t ret; + unsigned int idx; + + idx = SUBPAGE_IDX(addr); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__, + mmio, len, addr, idx); +#endif + ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], + addr + mmio->region_offset[idx][0][len]); + + return ret; +} + +static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr, + uint32_t value, unsigned int len) +{ + unsigned int idx; + + idx = SUBPAGE_IDX(addr); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__, + mmio, len, addr, idx, value); +#endif + (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], + addr + mmio->region_offset[idx][1][len], + value); +} + +static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 0); +} + +static void subpage_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 0); +} + +static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 1); +} + +static void subpage_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 1); +} + +static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 2); +} + +static void subpage_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 2); +} + +static CPUReadMemoryFunc * const subpage_read[] = { + &subpage_readb, + &subpage_readw, + &subpage_readl, +}; + +static CPUWriteMemoryFunc * const subpage_write[] = { + &subpage_writeb, + &subpage_writew, + &subpage_writel, +}; + +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + ram_addr_t memory, ram_addr_t region_offset) +{ + int idx, eidx; + unsigned int i; + + if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE) + return -1; + idx = SUBPAGE_IDX(start); + eidx = SUBPAGE_IDX(end); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__, + mmio, start, end, idx, eidx, memory); +#endif + memory >>= IO_MEM_SHIFT; + for (; idx <= eidx; idx++) { + for (i = 0; i < 4; i++) { + if (io_mem_read[memory][i]) { + mmio->mem_read[idx][i] = &io_mem_read[memory][i]; + mmio->opaque[idx][0][i] = io_mem_opaque[memory]; + mmio->region_offset[idx][0][i] = region_offset; + } + if (io_mem_write[memory][i]) { + mmio->mem_write[idx][i] = &io_mem_write[memory][i]; + mmio->opaque[idx][1][i] = io_mem_opaque[memory]; + mmio->region_offset[idx][1][i] = region_offset; + } + } + } + + return 0; +} + +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory, ram_addr_t region_offset) +{ + subpage_t *mmio; + int subpage_memory; + + mmio = qemu_mallocz(sizeof(subpage_t)); + + mmio->base = base; + subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, + mmio, base, TARGET_PAGE_SIZE, subpage_memory); +#endif + *phys = subpage_memory | IO_MEM_SUBPAGE; + subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory, + region_offset); + + return mmio; +} + +static int get_free_io_mem_idx(void) +{ + int i; + + for (i = 0; i>= IO_MEM_SHIFT; + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + } + + for(i = 0;i < 3; i++) { + if (!mem_read[i] || !mem_write[i]) + subwidth = IO_MEM_SUBWIDTH; + io_mem_read[io_index][i] = mem_read[i]; + io_mem_write[io_index][i] = mem_write[i]; + } + io_mem_opaque[io_index] = opaque; + return (io_index << IO_MEM_SHIFT) | subwidth; +} + +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque) +{ + return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque); +} + +void cpu_unregister_io_memory(int io_table_address) +{ + int i; + int io_index = io_table_address >> IO_MEM_SHIFT; + + for (i=0;i < 3; i++) { + io_mem_read[io_index][i] = unassigned_mem_read[i]; + io_mem_write[io_index][i] = unassigned_mem_write[i]; + } + io_mem_opaque[io_index] = NULL; + io_mem_used[io_index] = 0; +} + +static void io_mem_init(void) +{ + int i; + + cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL); + for (i=0; i<5; i++) + io_mem_used[i] = 1; + + io_mem_watch = cpu_register_io_memory(watch_mem_read, + watch_mem_write, NULL); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + +/* physical memory access (slow version, mainly for debug) */ +#if defined(CONFIG_USER_ONLY) +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + int l, flags; + target_ulong page; + void * p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = page_get_flags(page); + if (!(flags & PAGE_VALID)) + return; + if (is_write) { + if (!(flags & PAGE_WRITE)) + return; + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_WRITE, addr, l, 0))) + /* FIXME - should this return an error rather than just fail? */ + return; + memcpy(p, buf, l); + unlock_user(p, addr, l); + } else { + if (!(flags & PAGE_READ)) + return; + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_READ, addr, l, 1))) + /* FIXME - should this return an error rather than just fail? */ + return; + memcpy(buf, p, l); + unlock_user(p, addr, 0); + } + len -= l; + buf += l; + addr += l; + } +} + +#else +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + int l, io_index; + uint8_t *ptr; + uint32_t val; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if (is_write) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + target_phys_addr_t addr1 = addr; + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + /* XXX: could force cpu_single_env to NULL to avoid + potential bugs */ + if (l >= 4 && ((addr1 & 3) == 0)) { + /* 32 bit write access */ + val = ldl_p(buf); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val); + l = 4; + } else if (l >= 2 && ((addr1 & 1) == 0)) { + /* 16 bit write access */ + val = lduw_p(buf); + io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val); + l = 2; + } else { + /* 8 bit write access */ + val = ldub_p(buf); + io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val); + l = 1; + } + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = qemu_get_ram_ptr(addr1); + memcpy(ptr, buf, l); + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } + } else { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + target_phys_addr_t addr1 = addr; + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + if (l >= 4 && ((addr1 & 3) == 0)) { + /* 32 bit read access */ + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1); + stl_p(buf, val); + l = 4; + } else if (l >= 2 && ((addr1 & 1) == 0)) { + /* 16 bit read access */ + val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1); + stw_p(buf, val); + l = 2; + } else { + /* 8 bit read access */ + val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1); + stb_p(buf, val); + l = 1; + } + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + memcpy(buf, ptr, l); + } + } + len -= l; + buf += l; + addr += l; + } +} + +/* used for ROM loading : can write in RAM and ROM */ +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + int l; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* do nothing */ + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* ROM/RAM case */ + ptr = qemu_get_ram_ptr(addr1); + memcpy(ptr, buf, l); + } + len -= l; + buf += l; + addr += l; + } +} + +typedef struct { + void *buffer; + target_phys_addr_t addr; + target_phys_addr_t len; +} BounceBuffer; + +static BounceBuffer bounce; + +typedef struct MapClient { + void *opaque; + void (*callback)(void *opaque); + QLIST_ENTRY(MapClient) link; +} MapClient; + +static QLIST_HEAD(map_client_list, MapClient) map_client_list + = QLIST_HEAD_INITIALIZER(map_client_list); + +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)) +{ + MapClient *client = qemu_malloc(sizeof(*client)); + + client->opaque = opaque; + client->callback = callback; + QLIST_INSERT_HEAD(&map_client_list, client, link); + return client; +} + +void cpu_unregister_map_client(void *_client) +{ + MapClient *client = (MapClient *)_client; + + QLIST_REMOVE(client, link); + qemu_free(client); +} + +static void cpu_notify_map_clients(void) +{ + MapClient *client; + + while (!QLIST_EMPTY(&map_client_list)) { + client = QLIST_FIRST(&map_client_list); + client->callback(client->opaque); + cpu_unregister_map_client(client); + } +} + +/* Map a physical memory region into a host virtual address. + * May map a subset of the requested range, given by and returned in *plen. + * May return NULL if resources needed to perform the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. + */ +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write) +{ + target_phys_addr_t len = *plen; + target_phys_addr_t done = 0; + int l; + uint8_t *ret = NULL; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + unsigned long addr1; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + if (done || bounce.buffer) { + break; + } + bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); + bounce.addr = addr; + bounce.len = l; + if (!is_write) { + cpu_physical_memory_rw(addr, bounce.buffer, l, 0); + } + ptr = bounce.buffer; + } else { + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + ptr = qemu_get_ram_ptr(addr1); + } + if (!done) { + ret = ptr; + } else if (ret + done != ptr) { + break; + } + + len -= l; + addr += l; + done += l; + } + *plen = done; + return ret; +} + +/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). + * Will also mark the memory as dirty if is_write == 1. access_len gives + * the amount of memory that was actually read or written by the caller. + */ +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) +{ + if (buffer != bounce.buffer) { + if (is_write) { + ram_addr_t addr1 = qemu_ram_addr_from_host(buffer); + while (access_len) { + unsigned l; + l = TARGET_PAGE_SIZE; + if (l > access_len) + l = access_len; + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + addr1 += l; + access_len -= l; + } + } + return; + } + if (is_write) { + cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len); + } + qemu_free(bounce.buffer); + bounce.buffer = NULL; + cpu_notify_map_clients(); +} + +/* warning: addr must be aligned */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint32_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldl_p(ptr); + } + return val; +} + +/* warning: addr must be aligned */ +uint64_t ldq_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint64_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#ifdef TARGET_WORDS_BIGENDIAN + val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32; + val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4); +#else + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32; +#endif + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldq_p(ptr); + } + return val; +} + +/* XXX: optimize */ +uint32_t ldub_phys(target_phys_addr_t addr) +{ + uint8_t val; + cpu_physical_memory_read(addr, &val, 1); + return val; +} + +/* XXX: optimize */ +uint32_t lduw_phys(target_phys_addr_t addr) +{ + uint16_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 2); + return tswap16(val); +} + +/* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + ptr = qemu_get_ram_ptr(addr1); + stl_p(ptr, val); + + if (unlikely(in_migration)) { + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } + } +} + +void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val); +#else + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32); +#endif + } else { + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + stq_p(ptr, val); + } +} + +/* warning: addr must be aligned */ +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = qemu_get_ram_ptr(addr1); + stl_p(ptr, val); + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } +} + +/* XXX: optimize */ +void stb_phys(target_phys_addr_t addr, uint32_t val) +{ + uint8_t v = val; + cpu_physical_memory_write(addr, &v, 1); +} + +/* XXX: optimize */ +void stw_phys(target_phys_addr_t addr, uint32_t val) +{ + uint16_t v = tswap16(val); + cpu_physical_memory_write(addr, (const uint8_t *)&v, 2); +} + +/* XXX: optimize */ +void stq_phys(target_phys_addr_t addr, uint64_t val) +{ + val = tswap64(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); +} + +#endif + +/* virtual memory access for debug (includes writing to ROM) */ +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int l; + target_phys_addr_t phys_addr; + target_ulong page; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + phys_addr = cpu_get_phys_page_debug(env, page); + /* if no physical page mapped, return an error */ + if (phys_addr == -1) + return -1; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + phys_addr += (addr & ~TARGET_PAGE_MASK); +#if !defined(CONFIG_USER_ONLY) + if (is_write) + cpu_physical_memory_write_rom(phys_addr, buf, l); + else +#endif + cpu_physical_memory_rw(phys_addr, buf, l, is_write); + len -= l; + buf += l; + addr += l; + } + return 0; +} + +/* in deterministic execution mode, instructions doing device I/Os + must be at the end of the TB */ +void cpu_io_recompile(CPUState *env, void *retaddr) +{ + TranslationBlock *tb; + uint32_t n, cflags; + target_ulong pc, cs_base; + uint64_t flags; + + tb = tb_find_pc((unsigned long)retaddr); + if (!tb) { + cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", + retaddr); + } + n = env->icount_decr.u16.low + tb->icount; + cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); + /* Calculate how many instructions had been executed before the fault + occurred. */ + n = n - env->icount_decr.u16.low; + /* Generate a new TB ending on the I/O insn. */ + n++; + /* On MIPS and SH, delay slot instructions can only be restarted if + they were already the first instruction in the TB. If this is not + the first instruction in a TB then re-execute the preceding + branch. */ +#if defined(TARGET_MIPS) + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { + env->active_tc.PC -= 4; + env->icount_decr.u16.low++; + env->hflags &= ~MIPS_HFLAG_BMASK; + } +#elif defined(TARGET_SH4) + if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 + && n > 1) { + env->pc -= 2; + env->icount_decr.u16.low++; + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + } +#endif + /* This should never happen. */ + if (n > CF_COUNT_MASK) + cpu_abort(env, "TB too big during recompile"); + + cflags = n | CF_LAST_IO; + pc = tb->pc; + cs_base = tb->cs_base; + flags = tb->flags; + tb_phys_invalidate(tb, -1); + /* FIXME: In theory this could raise an exception. In practice + we have already translated the block once so it's probably ok. */ + tb_gen_code(env, pc, cs_base, flags, cflags); + /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not + the first in the TB) then we end up generating a whole new TB and + repeating the fault, which is horribly inefficient. + Better would be to execute just this insn uncached, or generate a + second new TB. */ + cpu_resume_from_signal(env, NULL); +} + +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i, target_code_size, max_target_code_size; + int direct_jmp_count, direct_jmp2_count, cross_page; + TranslationBlock *tb; + + target_code_size = 0; + max_target_code_size = 0; + cross_page = 0; + direct_jmp_count = 0; + direct_jmp2_count = 0; + for(i = 0; i < nb_tbs; i++) { + tb = &tbs[i]; + target_code_size += tb->size; + if (tb->size > max_target_code_size) + max_target_code_size = tb->size; + if (tb->page_addr[1] != -1) + cross_page++; + if (tb->tb_next_offset[0] != 0xffff) { + direct_jmp_count++; + if (tb->tb_next_offset[1] != 0xffff) { + direct_jmp2_count++; + } + } + } + /* XXX: avoid using doubles ? */ + cpu_fprintf(f, "Translation buffer state:\n"); + cpu_fprintf(f, "gen code size %ld/%ld\n", + code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); + cpu_fprintf(f, "TB count %d/%d\n", + nb_tbs, code_gen_max_blocks); + cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", + nb_tbs ? target_code_size / nb_tbs : 0, + max_target_code_size); + cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, + target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", + cross_page, + nb_tbs ? (cross_page * 100) / nb_tbs : 0); + cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", + direct_jmp_count, + nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, + direct_jmp2_count, + nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + cpu_fprintf(f, "\nStatistics:\n"); + cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); + cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); + cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); + tcg_dump_info(f, cpu_fprintf); +} + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _cmmu +#define GETPC() NULL +#define env cpu_single_env +#define SOFTMMU_CODE_ACCESS + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +#undef env + +#endif diff --git a/qemu/qemu-git/.svn/text-base/feature_to_c.sh.svn-base b/qemu/qemu-git/.svn/text-base/feature_to_c.sh.svn-base new file mode 100644 index 0000000..dbf9f19 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/feature_to_c.sh.svn-base @@ -0,0 +1,76 @@ +#!/bin/sh + +# Convert text files to compilable C arrays. +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +output=$1 +shift + +if test -z "$output" || test -z "$1"; then + echo "Usage: $0 OUTPUTFILE INPUTFILE..." + exit 1 +fi + +if test -e "$output"; then + echo "Output file \"$output\" already exists; refusing to overwrite." + exit 1 +fi + +for input; do + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + + ${AWK:-awk} 'BEGIN { n = 0 + print "static const char '$arrayname'[] = {" + for (i = 0; i < 255; i++) + _ord_[sprintf("%c", i)] = i + } { + split($0, line, ""); + printf " " + for (i = 1; i <= length($0); i++) { + c = line[i] + if (c == "'\''") { + printf "'\''\\'\'''\'', " + } else if (c == "\\") { + printf "'\''\\\\'\'', " + } else if (_ord_[c] >= 32 && _ord_[c] < 127) { + printf "'\''%s'\'', ", c + } else { + printf "'\''\\%03o'\'', ", _ord_[c] + } + if (i % 10 == 0) + printf "\n " + } + printf "'\''\\n'\'', \n" + } END { + print " 0 };" + }' < $input >> $output +done + +echo >> $output +echo "extern const char *const xml_builtin[][2];" >> $output +echo "const char *const xml_builtin[][2] = {" >> $output + +for input; do + basename=`echo $input | sed 's,.*/,,'` + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + echo " { \"$basename\", $arrayname }," >> $output +done + +echo " { (char *)0, (char *)0 }" >> $output +echo "};" >> $output diff --git a/qemu/qemu-git/.svn/text-base/gdbstub.h.svn-base b/qemu/qemu-git/.svn/text-base/gdbstub.h.svn-base new file mode 100644 index 0000000..5740041 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/gdbstub.h.svn-base @@ -0,0 +1,35 @@ +#ifndef GDBSTUB_H +#define GDBSTUB_H + +#define DEFAULT_GDBSTUB_PORT "1234" + +/* GDB breakpoint/watchpoint types */ +#define GDB_BREAKPOINT_SW 0 +#define GDB_BREAKPOINT_HW 1 +#define GDB_WATCHPOINT_WRITE 2 +#define GDB_WATCHPOINT_READ 3 +#define GDB_WATCHPOINT_ACCESS 4 + +typedef void (*gdb_syscall_complete_cb)(CPUState *env, + target_ulong ret, target_ulong err); + +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); +int use_gdb_syscalls(void); +void gdb_set_stop_cpu(CPUState *env); +#ifdef CONFIG_USER_ONLY +int gdb_queuesig (void); +int gdb_handlesig (CPUState *, int); +void gdb_exit(CPUState *, int); +void gdb_signalled(CPUState *, int); +int gdbserver_start(int); +void gdbserver_fork(CPUState *); +#else +int gdbserver_start(const char *port); +#endif +/* Get or set a register. Returns the size of the register. */ +typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg); +void gdb_register_coprocessor(CPUState *env, + gdb_reg_cb get_reg, gdb_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); + +#endif diff --git a/qemu/qemu-git/.svn/text-base/gen-icount.h.svn-base b/qemu/qemu-git/.svn/text-base/gen-icount.h.svn-base new file mode 100644 index 0000000..3268f72 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/gen-icount.h.svn-base @@ -0,0 +1,46 @@ +/* Helpers for instruction counting code generation. */ + +static TCGArg *icount_arg; +static int icount_label; + +static inline void gen_icount_start(void) +{ + TCGv_i32 count; + + if (!use_icount) + return; + + icount_label = gen_new_label(); + count = tcg_temp_local_new_i32(); + tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32)); + /* This is a horrid hack to allow fixing up the value later. */ + icount_arg = gen_opparam_ptr + 1; + tcg_gen_subi_i32(count, count, 0xdeadbeef); + + tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label); + tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low)); + tcg_temp_free_i32(count); +} + +static void gen_icount_end(TranslationBlock *tb, int num_insns) +{ + if (use_icount) { + *icount_arg = num_insns; + gen_set_label(icount_label); + tcg_gen_exit_tb((long)tb + 2); + } +} + +static inline void gen_io_start(void) +{ + TCGv_i32 tmp = tcg_const_i32(1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free_i32(tmp); +} + +static inline void gen_io_end(void) +{ + TCGv_i32 tmp = tcg_const_i32(0); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free_i32(tmp); +} diff --git a/qemu/qemu-git/.svn/text-base/host-utils.c.svn-base b/qemu/qemu-git/.svn/text-base/host-utils.c.svn-base new file mode 100644 index 0000000..dc96123 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/host-utils.c.svn-base @@ -0,0 +1,105 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2007 Aurelien Jarno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "host-utils.h" + +//#define DEBUG_MULDIV + +/* Long integer helpers */ +#if !defined(__x86_64__) +static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; +} + +static void neg128 (uint64_t *plow, uint64_t *phigh) +{ + *plow = ~*plow; + *phigh = ~*phigh; + add128(plow, phigh, 1, 0); +} + +static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + uint32_t a0, a1, b0, b1; + uint64_t v; + + a0 = a; + a1 = a >> 32; + + b0 = b; + b1 = b >> 32; + + v = (uint64_t)a0 * (uint64_t)b0; + *plow = v; + *phigh = 0; + + v = (uint64_t)a0 * (uint64_t)b1; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b0; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b1; + *phigh += v; +} + +/* Unsigned 64x64 -> 128 multiplication */ +void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + mul64(plow, phigh, a, b); +#if defined(DEBUG_MULDIV) + printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} + +/* Signed 64x64 -> 128 multiplication */ +void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +{ + int sa, sb; + + sa = (a < 0); + if (sa) + a = -a; + sb = (b < 0); + if (sb) + b = -b; + mul64(plow, phigh, a, b); + if (sa ^ sb) { + neg128(plow, phigh); + } +#if defined(DEBUG_MULDIV) + printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} +#endif /* !defined(__x86_64__) */ diff --git a/qemu/qemu-git/.svn/text-base/host-utils.h.svn-base b/qemu/qemu-git/.svn/text-base/host-utils.h.svn-base new file mode 100644 index 0000000..0ddc176 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/host-utils.h.svn-base @@ -0,0 +1,236 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2007 Thiemo Seufer + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "osdep.h" + +#if defined(__x86_64__) +#define __HAVE_FAST_MULU64__ +static inline void mulu64(uint64_t *plow, uint64_t *phigh, + uint64_t a, uint64_t b) +{ + __asm__ ("mul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#define __HAVE_FAST_MULS64__ +static inline void muls64(uint64_t *plow, uint64_t *phigh, + int64_t a, int64_t b) +{ + __asm__ ("imul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#else +void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); +void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); +#endif + +/* Binary search for leading zeros. */ + +static inline int clz32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clz(val); + else + return 32; +#else + int cnt = 0; + + if (!(val & 0xFFFF0000U)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF000000U)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF0000000U)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC0000000U)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x80000000U)) { + cnt++; + val <<= 1; + } + if (!(val & 0x80000000U)) { + cnt++; + } + return cnt; +#endif +} + +static inline int clo32(uint32_t val) +{ + return clz32(~val); +} + +static inline int clz64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clzll(val); + else + return 64; +#else + int cnt = 0; + + if (!(val >> 32)) { + cnt += 32; + } else { + val >>= 32; + } + + return cnt + clz32(val); +#endif +} + +static inline int clo64(uint64_t val) +{ + return clz64(~val); +} + +static inline int ctz32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctz(val); + else + return 32; +#else + int cnt; + + cnt = 0; + if (!(val & 0x0000FFFFUL)) { + cnt += 16; + val >>= 16; + } + if (!(val & 0x000000FFUL)) { + cnt += 8; + val >>= 8; + } + if (!(val & 0x0000000FUL)) { + cnt += 4; + val >>= 4; + } + if (!(val & 0x00000003UL)) { + cnt += 2; + val >>= 2; + } + if (!(val & 0x00000001UL)) { + cnt++; + val >>= 1; + } + if (!(val & 0x00000001UL)) { + cnt++; + } + + return cnt; +#endif +} + +static inline int cto32(uint32_t val) +{ + return ctz32(~val); +} + +static inline int ctz64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctzll(val); + else + return 64; +#else + int cnt; + + cnt = 0; + if (!((uint32_t)val)) { + cnt += 32; + val >>= 32; + } + + return cnt + ctz32(val); +#endif +} + +static inline int cto64(uint64_t val) +{ + return ctz64(~val); +} + +static inline int ctpop8(uint8_t val) +{ + val = (val & 0x55) + ((val >> 1) & 0x55); + val = (val & 0x33) + ((val >> 2) & 0x33); + val = (val & 0x0f) + ((val >> 4) & 0x0f); + + return val; +} + +static inline int ctpop16(uint16_t val) +{ + val = (val & 0x5555) + ((val >> 1) & 0x5555); + val = (val & 0x3333) + ((val >> 2) & 0x3333); + val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f); + val = (val & 0x00ff) + ((val >> 8) & 0x00ff); + + return val; +} + +static inline int ctpop32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcount(val); +#else + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); + val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); + + return val; +#endif +} + +static inline int ctpop64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcountll(val); +#else + val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL); + val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL); + + return val; +#endif +} diff --git a/qemu/qemu-git/.svn/text-base/hostregs_helper.h.svn-base b/qemu/qemu-git/.svn/text-base/hostregs_helper.h.svn-base new file mode 100644 index 0000000..3a0bece --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/hostregs_helper.h.svn-base @@ -0,0 +1,61 @@ +/* + * Save/restore host registers. + * + * Copyright (c) 2007 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* The GCC global register variable extension is used to reserve some + host registers for use by generated code. However only the core parts of + the translation engine are compiled with these settings. We must manually + save/restore these registers when called from regular code. + It is not sufficient to save/restore T0 et. al. as these may be declared + with a datatype smaller than the actual register. */ + +#if defined(DECLARE_HOST_REGS) + +#define DO_REG(REG) \ + register host_reg_t reg_AREG##REG asm(AREG##REG); \ + volatile host_reg_t saved_AREG##REG; + +#elif defined(SAVE_HOST_REGS) + +#define DO_REG(REG) \ + __asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \ + saved_AREG##REG = reg_AREG##REG; + +#else + +#define DO_REG(REG) \ + reg_AREG##REG = saved_AREG##REG; \ + __asm__ __volatile__ ("" : : "r" (reg_AREG##REG)); + +#endif + +#ifdef AREG0 +DO_REG(0) +#endif + +#ifdef AREG1 +DO_REG(1) +#endif + +#ifdef AREG2 +DO_REG(2) +#endif + +#undef SAVE_HOST_REGS +#undef DECLARE_HOST_REGS +#undef DO_REG diff --git a/qemu/qemu-git/.svn/text-base/hppa-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/hppa-dis.c.svn-base new file mode 100644 index 0000000..9d96d72 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/hppa-dis.c.svn-base @@ -0,0 +1,2831 @@ +/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. + Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003, + 2005 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "dis-asm.h" + +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2003 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _LIBHPPA_H +#define _LIBHPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11, + R_HPPA_LTPSEL = 0x12, + R_HPPA_RTPSEL = 0x13 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL, + e_ltpsel = R_HPPA_LTPSEL, + e_rtpsel = R_HPPA_RTPSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) \ + (((a) >> 22) & 0x3ff) +#define HPPA_R_CONSTANT(a) \ + ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22)) +#define HPPA_R_ADDEND(r, c) \ + (((r) << 22) + ((c) & 0x3fffff)) + + +/* Some functions to manipulate PA instructions. */ + +/* Declare the functions with the unused attribute to avoid warnings. */ +static inline int sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED; +static inline bfd_signed_vma hppa_field_adjust + (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) + ATTRIBUTE_UNUSED; +static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED; + + +/* The *sign_extend functions are used to assemble various bitfields + taken from an instruction and return the resulting immediate + value. */ + +static inline int +sign_extend (int x, int len) +{ + int signbit = (1 << (len - 1)); + int mask = (signbit << 1) - 1; + return ((x & mask) ^ signbit) - signbit; +} + +static inline int +low_sign_extend (int x, int len) +{ + return (x >> 1) - ((x & 1) << (len - 1)); +} + + +/* The re_assemble_* functions prepare an immediate value for + insertion into an opcode. pa-risc uses all sorts of weird bitfields + in the instruction to hold the value. */ + +static inline int +sign_unext (int x, int len) +{ + int len_ones; + + len_ones = (1 << len) - 1; + + return x & len_ones; +} + +static inline int +low_sign_unext (int x, int len) +{ + int temp; + int sign; + + sign = (x >> (len-1)) & 1; + + temp = sign_unext (x, len-1); + + return (temp << 1) | sign; +} + +static inline int +re_assemble_3 (int as3) +{ + return (( (as3 & 4) << (13-2)) + | ((as3 & 3) << (13+1))); +} + +static inline int +re_assemble_12 (int as12) +{ + return (( (as12 & 0x800) >> 11) + | ((as12 & 0x400) >> (10 - 2)) + | ((as12 & 0x3ff) << (1 + 2))); +} + +static inline int +re_assemble_14 (int as14) +{ + return (( (as14 & 0x1fff) << 1) + | ((as14 & 0x2000) >> 13)); +} + +static inline int +re_assemble_16 (int as16) +{ + int s, t; + + /* Unusual 16-bit encoding, for wide mode only. */ + t = (as16 << 1) & 0xffff; + s = (as16 & 0x8000); + return (t ^ s ^ (s >> 1)) | (s >> 15); +} + +static inline int +re_assemble_17 (int as17) +{ + return (( (as17 & 0x10000) >> 16) + | ((as17 & 0x0f800) << (16 - 11)) + | ((as17 & 0x00400) >> (10 - 2)) + | ((as17 & 0x003ff) << (1 + 2))); +} + +static inline int +re_assemble_21 (int as21) +{ + return (( (as21 & 0x100000) >> 20) + | ((as21 & 0x0ffe00) >> 8) + | ((as21 & 0x000180) << 7) + | ((as21 & 0x00007c) << 14) + | ((as21 & 0x000003) << 12)); +} + +static inline int +re_assemble_22 (int as22) +{ + return (( (as22 & 0x200000) >> 21) + | ((as22 & 0x1f0000) << (21 - 16)) + | ((as22 & 0x00f800) << (16 - 11)) + | ((as22 & 0x000400) >> (10 - 2)) + | ((as22 & 0x0003ff) << (1 + 2))); +} + + +/* Handle field selectors for PA instructions. + The L and R (and LS, RS etc.) selectors are used in pairs to form a + full 32 bit address. eg. + + LDIL L'start,%r1 ; put left part into r1 + LDW R'start(%r1),%r2 ; add r1 and right part to form address + + This function returns sign extended values in all cases. +*/ + +static inline bfd_signed_vma +hppa_field_adjust (bfd_vma sym_val, + bfd_signed_vma addend, + enum hppa_reloc_field_selector_type_alt r_field) +{ + bfd_signed_vma value; + + value = sym_val + addend; + switch (r_field) + { + case e_fsel: + /* F: No change. */ + break; + + case e_nsel: + /* N: null selector. I don't really understand what this is all + about, but HP's documentation says "this indicates that zero + bits are to be used for the displacement on the instruction. + This fixup is used to identify three-instruction sequences to + access data (for importing shared library data)." */ + value = 0; + break; + + case e_lsel: + case e_nlsel: + /* L: Select top 21 bits. */ + value = value >> 11; + break; + + case e_rsel: + /* R: Select bottom 11 bits. */ + value = value & 0x7ff; + break; + + case e_lssel: + /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ + value = value + 0x400; + value = value >> 11; + break; + + case e_rssel: + /* RS: Select bottom 11 bits for LS. + We need to return a value such that 2048 * LS'x + RS'x == x. + ie. RS'x = x - ((x + 0x400) & -0x800) + this is just a sign extension from bit 21. */ + value = ((value & 0x7ff) ^ 0x400) - 0x400; + break; + + case e_ldsel: + /* LD: Round to next multiple of 2048 then select top 21 bits. + Yes, if we are already on a multiple of 2048, we go up to the + next one. RD in this case will be -2048. */ + value = value + 0x800; + value = value >> 11; + break; + + case e_rdsel: + /* RD: Set bits 0-20 to one. */ + value = value | -0x800; + break; + + case e_lrsel: + case e_nlrsel: + /* LR: L with rounding of the addend to nearest 8k. */ + value = sym_val + ((addend + 0x1000) & -0x2000); + value = value >> 11; + break; + + case e_rrsel: + /* RR: R with rounding of the addend to nearest 8k. + We need to return a value such that 2048 * LR'x + RR'x == x + ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) + . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) + . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ + value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); + break; + + default: + abort (); + } + return value; +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) (((insn) >> 26) & 0x3f) + +enum hppa_opcode_type +{ + /* None of the opcodes in the first group generate relocs, so we + aren't too concerned about them. */ + OP_SYSOP = 0x00, + OP_MEMMNG = 0x01, + OP_ALU = 0x02, + OP_NDXMEM = 0x03, + OP_SPOP = 0x04, + OP_DIAG = 0x05, + OP_FMPYADD = 0x06, + OP_UNDEF07 = 0x07, + OP_COPRW = 0x09, + OP_COPRDW = 0x0b, + OP_COPR = 0x0c, + OP_FLOAT = 0x0e, + OP_PRDSPEC = 0x0f, + OP_UNDEF15 = 0x15, + OP_UNDEF1d = 0x1d, + OP_FMPYSUB = 0x26, + OP_FPFUSED = 0x2e, + OP_SHEXDP0 = 0x34, + OP_SHEXDP1 = 0x35, + OP_SHEXDP2 = 0x36, + OP_UNDEF37 = 0x37, + OP_SHEXDP3 = 0x3c, + OP_SHEXDP4 = 0x3d, + OP_MULTMED = 0x3e, + OP_UNDEF3f = 0x3f, + + OP_LDIL = 0x08, + OP_ADDIL = 0x0a, + + OP_LDO = 0x0d, + OP_LDB = 0x10, + OP_LDH = 0x11, + OP_LDW = 0x12, + OP_LDWM = 0x13, + OP_STB = 0x18, + OP_STH = 0x19, + OP_STW = 0x1a, + OP_STWM = 0x1b, + + OP_LDD = 0x14, + OP_STD = 0x1c, + + OP_FLDW = 0x16, + OP_LDWL = 0x17, + OP_FSTW = 0x1e, + OP_STWL = 0x1f, + + OP_COMBT = 0x20, + OP_COMIBT = 0x21, + OP_COMBF = 0x22, + OP_COMIBF = 0x23, + OP_CMPBDT = 0x27, + OP_ADDBT = 0x28, + OP_ADDIBT = 0x29, + OP_ADDBF = 0x2a, + OP_ADDIBF = 0x2b, + OP_CMPBDF = 0x2f, + OP_BVB = 0x30, + OP_BB = 0x31, + OP_MOVB = 0x32, + OP_MOVIB = 0x33, + OP_CMPIBD = 0x3b, + + OP_COMICLR = 0x24, + OP_SUBI = 0x25, + OP_ADDIT = 0x2c, + OP_ADDI = 0x2d, + + OP_BE = 0x38, + OP_BLE = 0x39, + OP_BL = 0x3a +}; + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static inline int +hppa_rebuild_insn (int insn, int value, int r_format) +{ + switch (r_format) + { + case 11: + return (insn & ~ 0x7ff) | low_sign_unext (value, 11); + + case 12: + return (insn & ~ 0x1ffd) | re_assemble_12 (value); + + + case 10: + return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8); + + case -11: + return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4); + + case 14: + return (insn & ~ 0x3fff) | re_assemble_14 (value); + + + case -10: + return (insn & ~ 0xfff1) | re_assemble_16 (value & -8); + + case -16: + return (insn & ~ 0xfff9) | re_assemble_16 (value & -4); + + case 16: + return (insn & ~ 0xffff) | re_assemble_16 (value); + + + case 17: + return (insn & ~ 0x1f1ffd) | re_assemble_17 (value); + + case 21: + return (insn & ~ 0x1fffff) | re_assemble_21 (value); + + case 22: + return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value); + + case 32: + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _LIBHPPA_H */ +/* Table of opcodes for the PA-RISC. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS/GDB 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. +If not, see . */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ + +/* There are two kinds of delay slot nullification: normal which is + * controled by the nullification bit, and conditional, which depends + * on the direction of the branch and its success or failure. + * + * NONE is unfortunately #defined in the hiux system include files. + * #undef it away. + */ +#undef NONE +struct pa_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set... */ + unsigned long int mask; /* ... in these bits. */ + char *args; + enum pa_arch arch; + char flags; +}; + +/* Enables strict matching. Opcodes with match errors are skipped + when this bit is set. */ +#define FLAG_STRICT 0x1 + +/* + All hppa opcodes are 32 bits. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character for each operand of + the instruction. Characters used as a prefix allow any second character to + be used without conflicting with the main operand characters. + + Bit positions in this description follow HP usage of lsb = 31, + "at" is lsb of field. + + In the args field, the following characters must match exactly: + + '+,() ' + + In the args field, the following characters are unused: + + ' " - / 34 6789:; ' + '@ C M [\] ' + '` e g } ' + + Here are all the characters: + + ' !"#$%&'()*+-,./0123456789:;<=>?' + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + '`abcdefghijklmnopqrstuvwxyz{|}~ ' + +Kinds of operands: + x integer register field at 15. + b integer register field at 10. + t integer register field at 31. + a integer register field at 10 and 15 (for PERMH) + 5 5 bit immediate at 15. + s 2 bit space specifier at 17. + S 3 bit space specifier at 18. + V 5 bit immediate value at 31 + i 11 bit immediate value at 31 + j 14 bit immediate value at 31 + k 21 bit immediate value at 31 + l 16 bit immediate value at 31 (wide mode only, unusual encoding). + n nullification for branch instructions + N nullification for spop and copr instructions + w 12 bit branch displacement + W 17 bit branch displacement (PC relative) + X 22 bit branch displacement (PC relative) + z 17 bit branch displacement (just a number, not an address) + +Also these: + + . 2 bit shift amount at 25 + * 4 bit shift amount at 25 + p 5 bit shift count at 26 (to support the SHD instruction) encoded as + 31-p + ~ 6 bit shift count at 20,22:26 encoded as 63-~. + P 5 bit bit position at 26 + q 6 bit bit position at 20,22:26 + T 5 bit field length at 31 (encoded as 32-T) + % 6 bit field length at 23,27:31 (variable extract/deposit) + | 6 bit field length at 19,27:31 (fixed extract/deposit) + A 13 bit immediate at 18 (to support the BREAK instruction) + ^ like b, but describes a control register + ! sar (cr11) register + D 26 bit immediate at 31 (to support the DIAG instruction) + $ 9 bit immediate at 28 (to support POPBTS) + + v 3 bit Special Function Unit identifier at 25 + O 20 bit Special Function Unit operation split between 15 bits at 20 + and 5 bits at 31 + o 15 bit Special Function Unit operation at 20 + 2 22 bit Special Function Unit operation split between 17 bits at 20 + and 5 bits at 31 + 1 15 bit Special Function Unit operation split between 10 bits at 20 + and 5 bits at 31 + 0 10 bit Special Function Unit operation split between 5 bits at 20 + and 5 bits at 31 + u 3 bit coprocessor unit identifier at 25 + F Source Floating Point Operand Format Completer encoded 2 bits at 20 + I Source Floating Point Operand Format Completer encoded 1 bits at 20 + (for 0xe format FP instructions) + G Destination Floating Point Operand Format Completer encoded 2 bits at 18 + H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' + (very similar to 'F') + + r 5 bit immediate value at 31 (for the break instruction) + (very similar to V above, except the value is unsigned instead of + low_sign_ext) + R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) + (same as r above, except the value is in a different location) + U 10 bit immediate value at 15 (for SSM, RSM on pa2.0) + Q 5 bit immediate value at 10 (a bit position specified in + the bb instruction. It's the same as r above, except the + value is in a different location) + B 5 bit immediate value at 10 (a bit position specified in + the bb instruction. Similar to Q, but 64 bit handling is + different. + Z %r1 -- implicit target of addil instruction. + L ,%r2 completer for new syntax branch + { Source format completer for fcnv + _ Destination format completer for fcnv + h cbit for fcmp + = gfx tests for ftest + d 14 bit offset for single precision FP long load/store. + # 14 bit offset for double precision FP load long/store. + J Yet another 14 bit offset for load/store with ma,mb completers. + K Yet another 14 bit offset for load/store with ma,mb completers. + y 16 bit offset for word aligned load/store (PA2.0 wide). + & 16 bit offset for dword aligned load/store (PA2.0 wide). + < 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + > 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + Y %sr0,%r31 -- implicit target of be,l instruction. + @ implicit immediate value of 0 + +Completer operands all have 'c' as the prefix: + + cx indexed load and store completer. + cX indexed load and store completer. Like cx, but emits a space + after in disassembler. + cm short load and store completer. + cM short load and store completer. Like cm, but emits a space + after in disassembler. + cq long load and store completer (like cm, but inserted into a + different location in the target instruction). + cs store bytes short completer. + cA store bytes short completer. Like cs, but emits a space + after in disassembler. + ce long load/store completer for LDW/STW with a different encoding + than the others + cc load cache control hint + cd load and clear cache control hint + cC store cache control hint + co ordered access + + cp branch link and push completer + cP branch pop completer + cl branch link completer + cg branch gate completer + + cw read/write completer for PROBE + cW wide completer for MFCTL + cL local processor completer for cache control + cZ System Control Completer (to support LPA, LHA, etc.) + + ci correction completer for DCOR + ca add completer + cy 32 bit add carry completer + cY 64 bit add carry completer + cv signed overflow trap completer + ct trap on condition completer for ADDI, SUB + cT trap on condition completer for UADDCM + cb 32 bit borrow completer for SUB + cB 64 bit borrow completer for SUB + + ch left/right half completer + cH signed/unsigned saturation completer + cS signed/unsigned completer at 21 + cz zero/sign extension completer. + c* permutation completer + +Condition operands all have '?' as the prefix: + + ?f Floating point compare conditions (encoded as 5 bits at 31) + + ?a add conditions + ?A 64 bit add conditions + ?@ add branch conditions followed by nullify + ?d non-negated add branch conditions + ?D negated add branch conditions + ?w wide mode non-negated add branch conditions + ?W wide mode negated add branch conditions + + ?s compare/subtract conditions + ?S 64 bit compare/subtract conditions + ?t non-negated compare and branch conditions + ?n 32 bit compare and branch conditions followed by nullify + ?N 64 bit compare and branch conditions followed by nullify + ?Q 64 bit compare and branch conditions for CMPIB instruction + + ?l logical conditions + ?L 64 bit logical conditions + + ?b branch on bit conditions + ?B 64 bit branch on bit conditions + + ?x shift/extract/deposit conditions + ?X 64 bit shift/extract/deposit conditions + ?y shift/extract/deposit conditions followed by nullify for conditional + branches + + ?u unit conditions + ?U 64 bit unit conditions + +Floating point registers all have 'f' as a prefix: + + ft target register at 31 + fT target register with L/R halves at 31 + fa operand 1 register at 10 + fA operand 1 register with L/R halves at 10 + fX Same as fA, except prints a space before register during disasm + fb operand 2 register at 15 + fB operand 2 register with L/R halves at 15 + fC operand 3 register with L/R halves at 16:18,21:23 + fe Like fT, but encoding is different. + fE Same as fe, except prints a space before register during disasm. + fx target register at 15 (only for PA 2.0 long format FLDD/FSTD). + +Float registers for fmpyadd and fmpysub: + + fi mult operand 1 register at 10 + fj mult operand 2 register at 15 + fk mult target register at 20 + fl add/sub operand register at 25 + fm add/sub target register at 31 + +*/ + + +#if 0 +/* List of characters not to put a space after. Note that + "," is included, as the "spopN" operations use literal + commas in their completer sections. */ +static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}"; +#endif + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic be + consecutive. If they aren't, the assembler will bomb at runtime. + + * Immediate fields use pa_get_absolute_expression to parse the + string. It will generate a "bad expression" error if passed + a register name. Thus, register index variants of an opcode + need to precede immediate variants. + + * The disassembler does not care about the order of the opcodes + except in cases where implicit addressing is used. + + Here are the rules for ordering the opcodes of a mnemonic: + + 1) Opcodes with FLAG_STRICT should precede opcodes without + FLAG_STRICT. + + 2) Opcodes with FLAG_STRICT should be ordered as follows: + register index opcodes, short immediate opcodes, and finally + long immediate opcodes. When both pa10 and pa11 variants + of the same opcode are available, the pa10 opcode should + come first for correct architectural promotion. + + 3) When implicit addressing is available for an opcode, the + implicit opcode should precede the explicit opcode. + + 4) Opcodes without FLAG_STRICT should be ordered as follows: + register index opcodes, long immediate opcodes, and finally + short immediate opcodes. */ + +static const struct pa_opcode pa_opcodes[] = +{ + +/* Pseudo-instructions. */ + +{ "ldi", 0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */ +{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */ + +{ "cmpib", 0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT}, +{ "cmpib", 0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT}, +{ "comib", 0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comib", 0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +{ "cmpb", 0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT}, +{ "cmpb", 0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT}, +{ "comb", 0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comb", 0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +{ "addb", 0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT}, +{ "addb", 0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addb", 0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0}, +{ "addib", 0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT}, +{ "addib", 0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addib", 0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +{ "nop", 0x08000240, 0xffffffff, "", pa10, 0}, /* or 0,0,0 */ +{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10, 0}, /* or r,0,t */ +{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */ + +/* Loads and Stores for integer registers. */ + +{ "ldd", 0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldh", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldb", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "std", 0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "sth", 0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "stb", 0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldwa", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwa", 0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "stwa", 0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "ldda", 0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stdby", 0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT}, +{ "stdby", 0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0}, + +/* Immediate instructions. */ +{ "ldo", 0x34000000, 0xfc000000, "l(b),x", pa20w, 0}, +{ "ldo", 0x34000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldil", 0x20000000, 0xfc000000, "k,b", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b,Z", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b", pa10, 0}, + +/* Branching instructions. */ +{ "b", 0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT}, +{ "b", 0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT}, +{ "b", 0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8000000, 0xffe0e000, "nW", pa10, 0}, /* b,l foo,r0 */ +{ "bl", 0xe8000000, 0xfc00e000, "nW,b", pa10, 0}, +{ "gate", 0xe8002000, 0xfc00e000, "nW,b", pa10, 0}, +{ "blr", 0xe8004000, 0xfc00e001, "nx,b", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "n(b)", pa10, 0}, +{ "bve", 0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT}, +{ "bve", 0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "be", 0xe0000000, 0xfc000000, "nz(b)", pa10, 0}, +{ "ble", 0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "movb", 0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0}, +{ "movib", 0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0}, +{ "combt", 0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "combf", 0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "comibt", 0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "comibf", 0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "addbt", 0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addbf", 0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addibt", 0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "addibf", 0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "bb", 0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT}, +{ "bb", 0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT}, +{ "bvb", 0xc0004000, 0xffe04000, "?bnx,w", pa10, 0}, +{ "clrbts", 0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "popbts", 0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT}, +{ "pushnom", 0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "pushbts", 0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT}, + +/* Computation Instructions. */ + +{ "cmpclr", 0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT}, +{ "cmpclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT}, +{ "comclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "or", 0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "or", 0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "xor", 0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "xor", 0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "and", 0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "and", 0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "andcm", 0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "andcm", 0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "uxor", 0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT}, +{ "uxor", 0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcm", 0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcmt", 0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "dcor", 0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "idcor", 0x08000bc0, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "addi", 0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addio", 0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addit", 0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addito", 0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "add", 0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addl", 0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addo", 0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addc", 0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addco", 0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sub", 0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subo", 0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subb", 0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subbo", 0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subt", 0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subto", 0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "ds", 0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subi", 0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT}, +{ "subi", 0x94000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "subio", 0x94000800, 0xfc000800, "?si,b,x", pa10, 0}, +{ "cmpiclr", 0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT}, +{ "cmpiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT}, +{ "comiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "shladd", 0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT}, +{ "shladd", 0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT}, +{ "sh1add", 0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addl", 0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addo", 0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2add", 0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addl", 0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addo", 0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3add", 0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addl", 0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addo", 0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0}, + +/* Subword Operation Instructions. */ + +{ "hadd", 0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "havg", 0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT}, +{ "hshl", 0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT}, +{ "hshladd", 0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hshr", 0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT}, +{ "hshradd", 0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hsub", 0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "mixh", 0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "mixw", 0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "permh", 0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT}, + + +/* Extract and Deposit Instructions. */ + +{ "shrpd", 0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT}, +{ "shrpd", 0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT}, +{ "shrpw", 0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT}, +{ "shrpw", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT}, +{ "vshd", 0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0}, +{ "shd", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0}, +{ "extrd", 0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT}, +{ "extrd", 0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT}, +{ "extrw", 0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT}, +{ "extrw", 0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT}, +{ "vextru", 0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "vextrs", 0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "extru", 0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "extrs", 0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "depd", 0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT}, +{ "depd", 0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT}, +{ "depdi", 0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT}, +{ "depdi", 0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT}, +{ "depw", 0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT}, +{ "depw", 0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT}, +{ "zvdep", 0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "vdep", 0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "zdep", 0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "dep", 0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "zvdepi", 0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "vdepi", 0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "zdepi", 0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0}, +{ "depi", 0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0}, + +/* System Control Instructions. */ + +{ "break", 0x00000000, 0xfc001fe0, "r,A", pa10, 0}, +{ "rfi", 0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT}, +{ "rfi", 0x00000c00, 0xffffffff, "", pa10, 0}, +{ "rfir", 0x00000ca0, 0xffffffff, "", pa11, 0}, +{ "ssm", 0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "ssm", 0x00000d60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "rsm", 0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "rsm", 0x00000e60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "mtsm", 0x00001860, 0xffe0ffff, "x", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0}, +{ "mtsp", 0x00001820, 0xffe01fff, "x,S", pa10, 0}, +{ "mtctl", 0x00001840, 0xfc00ffff, "x,^", pa10, 0}, +{ "mtsarcm", 0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT}, +{ "mfia", 0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT}, +{ "mfsp", 0x000004a0, 0xffff1fe0, "S,t", pa10, 0}, +{ "mfctl", 0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT}, +{ "mfctl", 0x000008a0, 0xfc1fffe0, "^,t", pa10, 0}, +{ "sync", 0x00000400, 0xffffffff, "", pa10, 0}, +{ "syncdma", 0x00100400, 0xffffffff, "", pa10, 0}, +{ "probe", 0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT}, +{ "probe", 0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT}, +{ "prober", 0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "prober", 0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0}, +{ "lci", 0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0}, +{ "lci", 0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0}, +{ "pdtlb", 0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlb", 0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlb", 0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlbe", 0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlba", 0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlbp", 0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fic", 0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT}, +{ "fic", 0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fice", 0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "diag", 0x14000000, 0xfc000000, "D", pa10, 0}, +{ "idtlbt", 0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, +{ "iitlbt", 0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, + +/* These may be specific to certain versions of the PA. Joel claimed + they were 72000 (7200?) specific. However, I'm almost certain the + mtcpu/mfcpu were undocumented, but available in the older 700 machines. */ +{ "mtcpu", 0x14001600, 0xfc00ffff, "x,^", pa10, 0}, +{ "mfcpu", 0x14001A00, 0xfc00ffff, "^,x", pa10, 0}, +{ "tocen", 0x14403600, 0xffffffff, "", pa10, 0}, +{ "tocdis", 0x14401620, 0xffffffff, "", pa10, 0}, +{ "shdwgr", 0x14402600, 0xffffffff, "", pa10, 0}, +{ "grshdw", 0x14400620, 0xffffffff, "", pa10, 0}, + +/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either + the Timex FPU or the Mustang ERS (not sure which) manual. */ +{ "gfw", 0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfw", 0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0}, + +/* Floating Point Coprocessor Instructions. */ + +{ "fldw", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fadd", 0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fadd", 0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsub", 0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fsub", 0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fmpy", 0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fmpy", 0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fdiv", 0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fdiv", 0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsqrt", 0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fsqrt", 0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fabs", 0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fabs", 0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "frem", 0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "frem", 0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0}, +{ "frnd", 0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "frnd", 0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcpy", 0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fcpy", 0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcnvff", 0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvff", 0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvxf", 0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvxf", 0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfx", 0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfx", 0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfxt", 0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfxt", 0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fmpyfadd", 0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fmpynfadd", 0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0}, +{ "xmpyu", 0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0}, +{ "fmpyadd", 0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "fmpysub", 0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "ftest", 0x30002420, 0xffffffff, "", pa10, FLAG_STRICT}, +{ "ftest", 0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT}, +{ "ftest", 0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT}, +{ "fid", 0x30000000, 0xffffffff, "", pa11, 0}, + +/* Performance Monitor Instructions. */ + +{ "pmdis", 0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT}, +{ "pmenb", 0x30000680, 0xffffffff, "", pa20, FLAG_STRICT}, + +/* Assist Instructions. */ + +{ "spop0", 0x10000000, 0xfc000600, "v,ON", pa10, 0}, +{ "spop1", 0x10000200, 0xfc000600, "v,oNt", pa10, 0}, +{ "spop2", 0x10000400, 0xfc000600, "v,1Nb", pa10, 0}, +{ "spop3", 0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0}, +{ "copr", 0x30000000, 0xfc000000, "u,2N", pa10, 0}, +{ "cldw", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, + +/* More pseudo instructions which must follow the main table. */ +{ "call", 0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "call", 0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT}, +{ "ret", 0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT}, + +}; + +#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) + +/* SKV 12/18/92. Added some denotations for various operands. */ + +#define PA_IMM11_AT_31 'i' +#define PA_IMM14_AT_31 'j' +#define PA_IMM21_AT_31 'k' +#define PA_DISP12 'w' +#define PA_DISP17 'W' + +#define N_HPPA_OPERAND_FORMATS 5 + +/* Integer register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const reg_names[] = +{ + "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", + "sp", "r31" +}; + +/* Floating point register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const fp_reg_names[] = +{ + "fpsr", "fpe2", "fpe4", "fpe6", + "fr4", "fr5", "fr6", "fr7", "fr8", + "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", + "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", + "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31" +}; + +typedef unsigned int CORE_ADDR; + +/* Get at various relevent fields of an instruction word. */ + +#define MASK_5 0x1f +#define MASK_10 0x3ff +#define MASK_11 0x7ff +#define MASK_14 0x3fff +#define MASK_16 0xffff +#define MASK_21 0x1fffff + +/* These macros get bit fields using HP's numbering (MSB = 0). */ + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) + +#define GET_BIT(X, WHICH) \ + GET_FIELD (X, WHICH, WHICH) + +/* Some of these have been converted to 2-d arrays because they + consume less storage this way. If the maintenance becomes a + problem, convert them back to const 1-d pointer arrays. */ +static const char *const control_reg[] = +{ + "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", + "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", + "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", + "tr4", "tr5", "tr6", "tr7" +}; + +static const char *const compare_cond_names[] = +{ + "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev" +}; +static const char *const compare_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev" +}; +static const char *const cmpib_cond_64_names[] = +{ + ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>" +}; +static const char *const add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev" +}; +static const char *const add_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev" +}; +static const char *const wide_add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=", + ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>" +}; +static const char *const logical_cond_names[] = +{ + "", ",=", ",<", ",<=", 0, 0, 0, ",od", + ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; +static const char *const logical_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", + ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"}; +static const char *const unit_cond_names[] = +{ + "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc", + ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc" +}; +static const char *const unit_cond_64_names[] = +{ + "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc", + ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc" +}; +static const char *const shift_cond_names[] = +{ + "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" +}; +static const char *const shift_cond_64_names[] = +{ + "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" +}; +static const char *const bb_cond_64_names[] = +{ + ",*<", ",*>=" +}; +static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"}; +static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; +static const char *const short_bytes_compl_names[] = +{ + "", ",b,m", ",e", ",e,m" +}; +static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; +static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"}; +static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"}; +static const char *const float_comp_names[] = +{ + ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", + ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", + ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", + ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" +}; +static const char *const signed_unsigned_names[] = {",u", ",s"}; +static const char *const mix_half_names[] = {",l", ",r"}; +static const char *const saturation_names[] = {",us", ",ss", 0, ""}; +static const char *const read_write_names[] = {",r", ",w"}; +static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; + +/* For a bunch of different instructions form an index into a + completer name table. */ +#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ + GET_FIELD (insn, 18, 18) << 1) + +#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ + (GET_FIELD ((insn), 19, 19) ? 8 : 0)) + +/* Utility function to print registers. Put these first, so gcc's function + inlining can do its stuff. */ + +#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) + +static void +fput_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0"); +} + +static void +fput_fp_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_fp_reg_r (unsigned reg, disassemble_info *info) +{ + /* Special case floating point exception registers. */ + if (reg < 4) + (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); + else + (*info->fprintf_func) (info->stream, "%sR", + reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_creg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, control_reg[reg]); +} + +/* Print constants with sign. */ + +static void +fput_const (unsigned num, disassemble_info *info) +{ + if ((int) num < 0) + (*info->fprintf_func) (info->stream, "-%x", - (int) num); + else + (*info->fprintf_func) (info->stream, "%x", num); +} + +/* Routines to extract various sized constants out of hppa + instructions. */ + +/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ +static int +extract_3 (unsigned word) +{ + return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); +} + +static int +extract_5_load (unsigned word) +{ + return low_sign_extend (word >> 16 & MASK_5, 5); +} + +/* Extract the immediate field from a st{bhw}s instruction. */ + +static int +extract_5_store (unsigned word) +{ + return low_sign_extend (word & MASK_5, 5); +} + +/* Extract the immediate field from a break instruction. */ + +static unsigned +extract_5r_store (unsigned word) +{ + return (word & MASK_5); +} + +/* Extract the immediate field from a {sr}sm instruction. */ + +static unsigned +extract_5R_store (unsigned word) +{ + return (word >> 16 & MASK_5); +} + +/* Extract the 10 bit immediate field from a {sr}sm instruction. */ + +static unsigned +extract_10U_store (unsigned word) +{ + return (word >> 16 & MASK_10); +} + +/* Extract the immediate field from a bb instruction. */ + +static unsigned +extract_5Q_store (unsigned word) +{ + return (word >> 21 & MASK_5); +} + +/* Extract an 11 bit immediate field. */ + +static int +extract_11 (unsigned word) +{ + return low_sign_extend (word & MASK_11, 11); +} + +/* Extract a 14 bit immediate field. */ + +static int +extract_14 (unsigned word) +{ + return low_sign_extend (word & MASK_14, 14); +} + +/* Extract a 16 bit immediate field (PA2.0 wide only). */ + +static int +extract_16 (unsigned word) +{ + int m15, m0, m1; + + m0 = GET_BIT (word, 16); + m1 = GET_BIT (word, 17); + m15 = GET_BIT (word, 31); + word = (word >> 1) & 0x1fff; + word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); + return sign_extend (word, 16); +} + +/* Extract a 21 bit constant. */ + +static int +extract_21 (unsigned word) +{ + int val; + + word &= MASK_21; + word <<= 11; + val = GET_FIELD (word, 20, 20); + val <<= 11; + val |= GET_FIELD (word, 9, 19); + val <<= 2; + val |= GET_FIELD (word, 5, 6); + val <<= 5; + val |= GET_FIELD (word, 0, 4); + val <<= 2; + val |= GET_FIELD (word, 7, 8); + return sign_extend (val, 21) << 11; +} + +/* Extract a 12 bit constant from branch instructions. */ + +static int +extract_12 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | (word & 0x1) << 11, 12) << 2; +} + +/* Extract a 17 bit constant from branch instructions, returning the + 19 bit signed value. */ + +static int +extract_17 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | (word & 0x1) << 16, 17) << 2; +} + +static int +extract_22 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | GET_FIELD (word, 6, 10) << 16 + | (word & 0x1) << 21, 22) << 2; +} + +/* Print one instruction. */ + +int +print_insn_hppa (bfd_vma memaddr, disassemble_info *info) +{ + bfd_byte buffer[4]; + unsigned int insn, i; + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + insn = bfd_getb32 (buffer); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct pa_opcode *opcode = &pa_opcodes[i]; + + if ((insn & opcode->mask) == opcode->match) + { + const char *s; +#ifndef BFD64 + if (opcode->arch == pa20w) + continue; +#endif + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0])) + (*info->fprintf_func) (info->stream, " "); + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case 'x': + fput_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'a': + case 'b': + fput_reg (GET_FIELD (insn, 6, 10), info); + break; + case '^': + fput_creg (GET_FIELD (insn, 6, 10), info); + break; + case 't': + fput_reg (GET_FIELD (insn, 27, 31), info); + break; + + /* Handle floating point registers. */ + case 'f': + switch (*++s) + { + case 't': + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); + else + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'a': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + + /* 'fA' will not generate a space before the regsiter + name. Normally that is fine. Except that it + causes problems with xmpyu which has no FP format + completer. */ + case 'X': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'A': + if (GET_FIELD (insn, 24, 24)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + case 'b': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'B': + if (GET_FIELD (insn, 19, 19)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'C': + { + int reg = GET_FIELD (insn, 21, 22); + reg |= GET_FIELD (insn, 16, 18) << 2; + if (GET_FIELD (insn, 23, 23) != 0) + fput_fp_reg_r (reg, info); + else + fput_fp_reg (reg, info); + break; + } + case 'i': + { + int reg = GET_FIELD (insn, 6, 10); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'j': + { + int reg = GET_FIELD (insn, 11, 15); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'k': + { + int reg = GET_FIELD (insn, 27, 31); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'l': + { + int reg = GET_FIELD (insn, 21, 25); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'm': + { + int reg = GET_FIELD (insn, 16, 20); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + + /* 'fe' will not generate a space before the register + name. Normally that is fine. Except that it + causes problems with fstw fe,y(b) which has no FP + format completer. */ + case 'E': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'e': + if (GET_FIELD (insn, 30, 30)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'x': + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + } + break; + + case '5': + fput_const (extract_5_load (insn), info); + break; + case 's': + { + int space = GET_FIELD (insn, 16, 17); + /* Zero means implicit addressing, not use of sr0. */ + if (space != 0) + (*info->fprintf_func) (info->stream, "sr%d", space); + } + break; + + case 'S': + (*info->fprintf_func) (info->stream, "sr%d", + extract_3 (insn)); + break; + + /* Handle completers. */ + case 'c': + switch (*++s) + { + case 'x': + (*info->fprintf_func) + (info->stream, "%s", + index_compl_names[GET_COMPL (insn)]); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + index_compl_names[GET_COMPL (insn)]); + break; + case 'm': + (*info->fprintf_func) + (info->stream, "%s", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'M': + (*info->fprintf_func) + (info->stream, "%s ", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 'c': + case 'C': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",bc "); + break; + case 2: + (*info->fprintf_func) (info->stream, ",sl "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'd': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",co "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'o': + (*info->fprintf_func) (info->stream, ",o"); + break; + case 'g': + (*info->fprintf_func) (info->stream, ",gate"); + break; + case 'p': + (*info->fprintf_func) (info->stream, ",l,push"); + break; + case 'P': + (*info->fprintf_func) (info->stream, ",pop"); + break; + case 'l': + case 'L': + (*info->fprintf_func) (info->stream, ",l"); + break; + case 'w': + (*info->fprintf_func) + (info->stream, "%s ", + read_write_names[GET_FIELD (insn, 25, 25)]); + break; + case 'W': + (*info->fprintf_func) (info->stream, ",w "); + break; + case 'r': + if (GET_FIELD (insn, 23, 26) == 5) + (*info->fprintf_func) (info->stream, ",r"); + break; + case 'Z': + if (GET_FIELD (insn, 26, 26)) + (*info->fprintf_func) (info->stream, ",m "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'i': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",i"); + break; + case 'z': + if (!GET_FIELD (insn, 21, 21)) + (*info->fprintf_func) (info->stream, ",z"); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'Y': + (*info->fprintf_func) + (info->stream, ",dc%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'y': + (*info->fprintf_func) + (info->stream, ",c%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'v': + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 't': + (*info->fprintf_func) (info->stream, ",tc"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'B': + (*info->fprintf_func) (info->stream, ",db"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'b': + (*info->fprintf_func) (info->stream, ",b"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",tc"); + break; + case 'S': + /* EXTRD/W has a following condition. */ + if (*(s + 1) == '?') + (*info->fprintf_func) + (info->stream, "%s", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + else + (*info->fprintf_func) + (info->stream, "%s ", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + break; + case 'h': + (*info->fprintf_func) + (info->stream, "%s", + mix_half_names[GET_FIELD (insn, 17, 17)]); + break; + case 'H': + (*info->fprintf_func) + (info->stream, "%s ", + saturation_names[GET_FIELD (insn, 24, 25)]); + break; + case '*': + (*info->fprintf_func) + (info->stream, ",%d%d%d%d ", + GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21), + GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25)); + break; + + case 'q': + { + int m, a; + + m = GET_FIELD (insn, 28, 28); + a = GET_FIELD (insn, 29, 29); + + if (m && !a) + fputs_filtered (",ma ", info); + else if (m && a) + fputs_filtered (",mb ", info); + else + fputs_filtered (" ", info); + break; + } + + case 'J': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x16 || opc == 0x1e) + { + if (GET_FIELD (insn, 29, 29) == 0) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + break; + } + + case 'e': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x13 || opc == 0x1b) + { + if (GET_FIELD (insn, 18, 18) == 1) + fputs_filtered (",mb ", info); + else + fputs_filtered (",ma ", info); + } + else if (opc == 0x17 || opc == 0x1f) + { + if (GET_FIELD (insn, 31, 31) == 1) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + + break; + } + } + break; + + /* Handle conditions. */ + case '?': + { + s++; + switch (*s) + { + case 'f': + (*info->fprintf_func) + (info->stream, "%s ", + float_comp_names[GET_FIELD (insn, 27, 31)]); + break; + + /* These four conditions are for the set of instructions + which distinguish true/false conditions by opcode + rather than by the 'f' bit (sigh): comb, comib, + addb, addib. */ + case 't': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18)], info); + break; + case 'n': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 'N': + fputs_filtered + (compare_cond_64_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 2, 2) * 8], + info); + break; + case 'Q': + fputs_filtered + (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)], + info); + break; + case '@': + fputs_filtered + (add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_names[GET_COND (insn)]); + break; + case 'S': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_64_names[GET_COND (insn)]); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_names[GET_COND (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_64_names[GET_COND (insn)]); + break; + case 'd': + (*info->fprintf_func) + (info->stream, "%s", + add_cond_names[GET_FIELD (insn, 16, 18)]); + break; + + case 'W': + (*info->fprintf_func) + (info->stream, "%s", + wide_add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8]); + break; + + case 'l': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_names[GET_COND (insn)]); + break; + case 'L': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_64_names[GET_COND (insn)]); + break; + case 'u': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_names[GET_COND (insn)]); + break; + case 'U': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_64_names[GET_COND (insn)]); + break; + case 'y': + case 'x': + case 'b': + (*info->fprintf_func) + (info->stream, "%s", + shift_cond_names[GET_FIELD (insn, 16, 18)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + shift_cond_64_names[GET_FIELD (insn, 16, 18)]); + break; + case 'B': + (*info->fprintf_func) + (info->stream, "%s", + bb_cond_64_names[GET_FIELD (insn, 16, 16)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + } + break; + } + + case 'V': + fput_const (extract_5_store (insn), info); + break; + case 'r': + fput_const (extract_5r_store (insn), info); + break; + case 'R': + fput_const (extract_5R_store (insn), info); + break; + case 'U': + fput_const (extract_10U_store (insn), info); + break; + case 'B': + case 'Q': + fput_const (extract_5Q_store (insn), info); + break; + case 'i': + fput_const (extract_11 (insn), info); + break; + case 'j': + fput_const (extract_14 (insn), info); + break; + case 'k': + fputs_filtered ("L%", info); + fput_const (extract_21 (insn), info); + break; + case '<': + case 'l': + /* 16-bit long disp., PA2.0 wide only. */ + fput_const (extract_16 (insn), info); + break; + case 'n': + if (insn & 0x2) + (*info->fprintf_func) (info->stream, ",n "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'N': + if ((insn & 0x20) && s[1]) + (*info->fprintf_func) (info->stream, ",n "); + else if (insn & 0x20) + (*info->fprintf_func) (info->stream, ",n"); + else if (s[1]) + (*info->fprintf_func) (info->stream, " "); + break; + case 'w': + (*info->print_address_func) + (memaddr + 8 + extract_12 (insn), info); + break; + case 'W': + /* 17 bit PC-relative branch. */ + (*info->print_address_func) + ((memaddr + 8 + extract_17 (insn)), info); + break; + case 'z': + /* 17 bit displacement. This is an offset from a register + so it gets disasssembled as just a number, not any sort + of address. */ + fput_const (extract_17 (insn), info); + break; + + case 'Z': + /* addil %r1 implicit output. */ + fputs_filtered ("r1", info); + break; + + case 'Y': + /* be,l %sr0,%r31 implicit output. */ + fputs_filtered ("sr0,r31", info); + break; + + case '@': + (*info->fprintf_func) (info->stream, "0"); + break; + + case '.': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 24, 25)); + break; + case '*': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 25)); + break; + case '!': + fputs_filtered ("sar", info); + break; + case 'p': + (*info->fprintf_func) (info->stream, "%d", + 31 - GET_FIELD (insn, 22, 26)); + break; + case '~': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", 63 - num); + break; + } + case 'P': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 26)); + break; + case 'q': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case 'T': + (*info->fprintf_func) (info->stream, "%d", + 32 - GET_FIELD (insn, 27, 31)); + break; + case '%': + { + int num; + num = (GET_FIELD (insn, 23, 23) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '|': + { + int num; + num = (GET_FIELD (insn, 19, 19) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '$': + fput_const (GET_FIELD (insn, 20, 28), info); + break; + case 'A': + fput_const (GET_FIELD (insn, 6, 18), info); + break; + case 'D': + fput_const (GET_FIELD (insn, 6, 31), info); + break; + case 'v': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'O': + fput_const ((GET_FIELD (insn, 6,20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'o': + fput_const (GET_FIELD (insn, 6, 20), info); + break; + case '2': + fput_const ((GET_FIELD (insn, 6, 22) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '1': + fput_const ((GET_FIELD (insn, 11, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '0': + fput_const ((GET_FIELD (insn, 16, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'u': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'F': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == 'G' || s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 19, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 19, 20)]); + break; + case 'G': + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 17, 18)]); + break; + case 'H': + if (GET_FIELD (insn, 26, 26) == 1) + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[0]); + else + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[1]); + break; + case 'I': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 20, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 20, 20)]); + break; + + case 'J': + fput_const (extract_14 (insn), info); + break; + + case '#': + { + int sign = GET_FIELD (insn, 31, 31); + int imm10 = GET_FIELD (insn, 18, 27); + int disp; + + if (sign) + disp = (-1 << 10) | imm10; + else + disp = imm10; + + disp <<= 3; + fput_const (disp, info); + break; + } + case 'K': + case 'd': + { + int sign = GET_FIELD (insn, 31, 31); + int imm11 = GET_FIELD (insn, 18, 28); + int disp; + + if (sign) + disp = (-1 << 11) | imm11; + else + disp = imm11; + + disp <<= 2; + fput_const (disp, info); + break; + } + + case '>': + case 'y': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~3; + fput_const (disp, info); + break; + } + + case '&': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~7; + fput_const (disp, info); + break; + } + + case '_': + break; /* Dealt with by '{' */ + + case '{': + { + int sub = GET_FIELD (insn, 14, 16); + int df = GET_FIELD (insn, 17, 18); + int sf = GET_FIELD (insn, 19, 20); + const char * const * source = float_format_names; + const char * const * dest = float_format_names; + char *t = ""; + + if (sub == 4) + { + fputs_filtered (",UND ", info); + break; + } + if ((sub & 3) == 3) + t = ",t"; + if ((sub & 3) == 1) + source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + if (sub & 2) + dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + + (*info->fprintf_func) (info->stream, "%s%s%s ", + t, source[sf], dest[df]); + break; + } + + case 'm': + { + int y = GET_FIELD (insn, 16, 18); + + if (y != 1) + fput_const ((y ^ 1) - 1, info); + } + break; + + case 'h': + { + int cbit; + + cbit = GET_FIELD (insn, 16, 18); + + if (cbit > 0) + (*info->fprintf_func) (info->stream, ",%d", cbit - 1); + break; + } + + case '=': + { + int cond = GET_FIELD (insn, 27, 31); + + switch (cond) + { + case 0: fputs_filtered (" ", info); break; + case 1: fputs_filtered ("acc ", info); break; + case 2: fputs_filtered ("rej ", info); break; + case 5: fputs_filtered ("acc8 ", info); break; + case 6: fputs_filtered ("rej8 ", info); break; + case 9: fputs_filtered ("acc6 ", info); break; + case 13: fputs_filtered ("acc4 ", info); break; + case 17: fputs_filtered ("acc2 ", info); break; + default: break; + } + break; + } + + case 'X': + (*info->print_address_func) + (memaddr + 8 + extract_22 (insn), info); + break; + case 'L': + fputs_filtered (",rp", info); + break; + default: + (*info->fprintf_func) (info->stream, "%c", *s); + break; + } + } + return sizeof (insn); + } + } + (*info->fprintf_func) (info->stream, "#%8x", insn); + return sizeof (insn); +} diff --git a/qemu/qemu-git/.svn/text-base/hppa.ld.svn-base b/qemu/qemu-git/.svn/text-base/hppa.ld.svn-base new file mode 100644 index 0000000..9a4b22c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/hppa.ld.svn-base @@ -0,0 +1,213 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux", + "elf32-hppa-linux") +OUTPUT_ARCH(hppa:hppa1.1) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x08000240 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x08000240 + .fini : + { + KEEP (*(.fini)) + } =0x08000240 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .PARISC.unwind : { *(.PARISC.unwind) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .data : + { + PROVIDE ($global$ = .); + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/.svn/text-base/i386-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/i386-dis.c.svn-base new file mode 100644 index 0000000..b2af033 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/i386-dis.c.svn-base @@ -0,0 +1,6559 @@ +/* opcodes/i386-dis.c r1.126 */ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + July 1988 + modified by John Hassey (hassey@dg-rtp.dg.com) + x86-64 support added by Jan Hubicka (jh@suse.cz) + VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ + +/* The main tables describing the instructions is essentially a copy + of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + Programmers Manual. Usually, there is a capital letter, followed + by a small letter. The capital letter tell the addressing mode, + and the small letter tells about the operand size. Refer to + the Intel manual for details. */ + +#include +#include "dis-asm.h" +/* include/opcode/i386.h r1.78 */ + +/* opcode/i386.h -- Intel 80386 opcode macros + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived + ix86 Unix assemblers, generate floating point instructions with + reversed source and destination registers in certain cases. + Unfortunately, gcc and possibly many other programs use this + reversed syntax, so we're stuck with it. + + eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but + `fsub %st,%st(3)' results in st(3) = st - st(3), rather than + the expected st(3) = st(3) - st + + This happens with all the non-commutative arithmetic floating point + operations with two register operands, where the source register is + %st, and destination register is %st(i). + + The affected opcode map is dceX, dcfX, deeX, defX. */ + +#ifndef SYSV386_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes at your peril. gcc generates SystemV/386 + compatible instructions. */ +#define SYSV386_COMPAT 1 +#endif +#ifndef OLDGCC_COMPAT +/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could + generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands + reversed. */ +#define OLDGCC_COMPAT SYSV386_COMPAT +#endif + +#define MOV_AX_DISP32 0xa0 +#define POP_SEG_SHORT 0x07 +#define JUMP_PC_RELATIVE 0xeb +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +/* The opcode for the fwait instruction, which disassembler treats as a + prefix when it can. */ +#define FWAIT_OPCODE 0x9b +#define ADDR_PREFIX_OPCODE 0x67 +#define DATA_PREFIX_OPCODE 0x66 +#define LOCK_PREFIX_OPCODE 0xf0 +#define CS_PREFIX_OPCODE 0x2e +#define DS_PREFIX_OPCODE 0x3e +#define ES_PREFIX_OPCODE 0x26 +#define FS_PREFIX_OPCODE 0x64 +#define GS_PREFIX_OPCODE 0x65 +#define SS_PREFIX_OPCODE 0x36 +#define REPNE_PREFIX_OPCODE 0xf2 +#define REPE_PREFIX_OPCODE 0xf3 + +#define TWO_BYTE_OPCODE_ESCAPE 0x0f +#define NOP_OPCODE (char) 0x90 + +/* register numbers */ +#define EBP_REG_NUM 5 +#define ESP_REG_NUM 4 + +/* modrm_byte.regmem for twobyte escape */ +#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM +/* index_base_byte.index for no index register addressing */ +#define NO_INDEX_REGISTER ESP_REG_NUM +/* index_base_byte.base for no base register addressing */ +#define NO_BASE_REGISTER EBP_REG_NUM +#define NO_BASE_REGISTER_16 6 + +/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ +#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ +#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) + +/* x86-64 extension prefix. */ +#define REX_OPCODE 0x40 + +/* Indicates 64 bit operand size. */ +#define REX_W 8 +/* High extension to reg field of modrm byte. */ +#define REX_R 4 +/* High extension to SIB index field. */ +#define REX_X 2 +/* High extension to base field of modrm or SIB, or reg field of opcode. */ +#define REX_B 1 + +/* max operands per insn */ +#define MAX_OPERANDS 4 + +/* max immediates per insn (lcall, ljmp, insertq, extrq) */ +#define MAX_IMMEDIATE_OPERANDS 2 + +/* max memory refs per insn (string ops) */ +#define MAX_MEMORY_OPERANDS 2 + +/* max size of insn mnemonics. */ +#define MAX_MNEM_SIZE 16 + +/* max size of register name in insn mnemonics. */ +#define MAX_REG_NAME_SIZE 8 + +/* opcodes/i386-dis.c r1.126 */ +#include "qemu-common.h" + +#include + +static int fetch_data (struct disassemble_info *, bfd_byte *); +static void ckprefix (void); +static const char *prefix_name (int, int); +static int print_insn (bfd_vma, disassemble_info *); +static void dofloat (int); +static void OP_ST (int, int); +static void OP_STi (int, int); +static int putop (const char *, int); +static void oappend (const char *); +static void append_seg (void); +static void OP_indirE (int, int); +static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp); +static void print_displacement (char *, bfd_vma); +static void OP_E (int, int); +static void OP_G (int, int); +static bfd_vma get64 (void); +static bfd_signed_vma get32 (void); +static bfd_signed_vma get32s (void); +static int get16 (void); +static void set_op (bfd_vma, int); +static void OP_REG (int, int); +static void OP_IMREG (int, int); +static void OP_I (int, int); +static void OP_I64 (int, int); +static void OP_sI (int, int); +static void OP_J (int, int); +static void OP_SEG (int, int); +static void OP_DIR (int, int); +static void OP_OFF (int, int); +static void OP_OFF64 (int, int); +static void ptr_reg (int, int); +static void OP_ESreg (int, int); +static void OP_DSreg (int, int); +static void OP_C (int, int); +static void OP_D (int, int); +static void OP_T (int, int); +static void OP_R (int, int); +static void OP_MMX (int, int); +static void OP_XMM (int, int); +static void OP_EM (int, int); +static void OP_EX (int, int); +static void OP_EMC (int,int); +static void OP_MXC (int,int); +static void OP_MS (int, int); +static void OP_XS (int, int); +static void OP_M (int, int); +static void OP_VMX (int, int); +static void OP_0fae (int, int); +static void OP_0f07 (int, int); +static void NOP_Fixup1 (int, int); +static void NOP_Fixup2 (int, int); +static void OP_3DNowSuffix (int, int); +static void OP_SIMD_Suffix (int, int); +static void SIMD_Fixup (int, int); +static void PNI_Fixup (int, int); +static void SVME_Fixup (int, int); +static void INVLPG_Fixup (int, int); +static void BadOp (void); +static void VMX_Fixup (int, int); +static void REP_Fixup (int, int); +static void CMPXCHG8B_Fixup (int, int); +static void XMM_Fixup (int, int); +static void CRC32_Fixup (int, int); + +struct dis_private { + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAX_MNEM_SIZE]; + bfd_vma insn_start; + int orig_sizeflag; + jmp_buf bailout; +}; + +enum address_mode +{ + mode_16bit, + mode_32bit, + mode_64bit +}; + +static enum address_mode address_mode; + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* REX prefix the current instruction. See below. */ +static int rex; +/* Bits of REX we've already used. */ +static int rex_used; +/* Mark parts used in the REX prefix. When we are testing for + empty prefix (for 8bit register REX extension), just mask it + out. Otherwise test for REX bit is excuse for existence of REX + only in case value is nonzero. */ +#define USED_REX(value) \ + { \ + if (value) \ + { \ + if ((rex & value)) \ + rex_used |= (value) | REX_OPCODE; \ + } \ + else \ + rex_used |= REX_OPCODE; \ + } + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct dis_private *priv = (struct dis_private *) info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + if (addr <= priv->the_buffer + MAX_MNEM_SIZE) + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + else + status = -1; + if (status != 0) + { + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define XX { NULL, 0 } + +#define Eb { OP_E, b_mode } +#define Ev { OP_E, v_mode } +#define Ed { OP_E, d_mode } +#define Edq { OP_E, dq_mode } +#define Edqw { OP_E, dqw_mode } +#define Edqb { OP_E, dqb_mode } +#define Edqd { OP_E, dqd_mode } +#define indirEv { OP_indirE, stack_v_mode } +#define indirEp { OP_indirE, f_mode } +#define stackEv { OP_E, stack_v_mode } +#define Em { OP_E, m_mode } +#define Ew { OP_E, w_mode } +#define M { OP_M, 0 } /* lea, lgdt, etc. */ +#define Ma { OP_M, v_mode } +#define Mp { OP_M, f_mode } /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Mq { OP_M, q_mode } +#define Gb { OP_G, b_mode } +#define Gv { OP_G, v_mode } +#define Gd { OP_G, d_mode } +#define Gdq { OP_G, dq_mode } +#define Gm { OP_G, m_mode } +#define Gw { OP_G, w_mode } +#define Rd { OP_R, d_mode } +#define Rm { OP_R, m_mode } +#define Ib { OP_I, b_mode } +#define sIb { OP_sI, b_mode } /* sign extened byte */ +#define Iv { OP_I, v_mode } +#define Iq { OP_I, q_mode } +#define Iv64 { OP_I64, v_mode } +#define Iw { OP_I, w_mode } +#define I1 { OP_I, const_1_mode } +#define Jb { OP_J, b_mode } +#define Jv { OP_J, v_mode } +#define Cm { OP_C, m_mode } +#define Dm { OP_D, m_mode } +#define Td { OP_T, d_mode } + +#define RMeAX { OP_REG, eAX_reg } +#define RMeBX { OP_REG, eBX_reg } +#define RMeCX { OP_REG, eCX_reg } +#define RMeDX { OP_REG, eDX_reg } +#define RMeSP { OP_REG, eSP_reg } +#define RMeBP { OP_REG, eBP_reg } +#define RMeSI { OP_REG, eSI_reg } +#define RMeDI { OP_REG, eDI_reg } +#define RMrAX { OP_REG, rAX_reg } +#define RMrBX { OP_REG, rBX_reg } +#define RMrCX { OP_REG, rCX_reg } +#define RMrDX { OP_REG, rDX_reg } +#define RMrSP { OP_REG, rSP_reg } +#define RMrBP { OP_REG, rBP_reg } +#define RMrSI { OP_REG, rSI_reg } +#define RMrDI { OP_REG, rDI_reg } +#define RMAL { OP_REG, al_reg } +#define RMAL { OP_REG, al_reg } +#define RMCL { OP_REG, cl_reg } +#define RMDL { OP_REG, dl_reg } +#define RMBL { OP_REG, bl_reg } +#define RMAH { OP_REG, ah_reg } +#define RMCH { OP_REG, ch_reg } +#define RMDH { OP_REG, dh_reg } +#define RMBH { OP_REG, bh_reg } +#define RMAX { OP_REG, ax_reg } +#define RMDX { OP_REG, dx_reg } + +#define eAX { OP_IMREG, eAX_reg } +#define eBX { OP_IMREG, eBX_reg } +#define eCX { OP_IMREG, eCX_reg } +#define eDX { OP_IMREG, eDX_reg } +#define eSP { OP_IMREG, eSP_reg } +#define eBP { OP_IMREG, eBP_reg } +#define eSI { OP_IMREG, eSI_reg } +#define eDI { OP_IMREG, eDI_reg } +#define AL { OP_IMREG, al_reg } +#define CL { OP_IMREG, cl_reg } +#define DL { OP_IMREG, dl_reg } +#define BL { OP_IMREG, bl_reg } +#define AH { OP_IMREG, ah_reg } +#define CH { OP_IMREG, ch_reg } +#define DH { OP_IMREG, dh_reg } +#define BH { OP_IMREG, bh_reg } +#define AX { OP_IMREG, ax_reg } +#define DX { OP_IMREG, dx_reg } +#define zAX { OP_IMREG, z_mode_ax_reg } +#define indirDX { OP_IMREG, indir_dx_reg } + +#define Sw { OP_SEG, w_mode } +#define Sv { OP_SEG, v_mode } +#define Ap { OP_DIR, 0 } +#define Ob { OP_OFF64, b_mode } +#define Ov { OP_OFF64, v_mode } +#define Xb { OP_DSreg, eSI_reg } +#define Xv { OP_DSreg, eSI_reg } +#define Xz { OP_DSreg, eSI_reg } +#define Yb { OP_ESreg, eDI_reg } +#define Yv { OP_ESreg, eDI_reg } +#define DSBX { OP_DSreg, eBX_reg } + +#define es { OP_REG, es_reg } +#define ss { OP_REG, ss_reg } +#define cs { OP_REG, cs_reg } +#define ds { OP_REG, ds_reg } +#define fs { OP_REG, fs_reg } +#define gs { OP_REG, gs_reg } + +#define MX { OP_MMX, 0 } +#define XM { OP_XMM, 0 } +#define EM { OP_EM, v_mode } +#define EMd { OP_EM, d_mode } +#define EMq { OP_EM, q_mode } +#define EXd { OP_EX, d_mode } +#define EXq { OP_EX, q_mode } +#define EXx { OP_EX, x_mode } +#define MS { OP_MS, v_mode } +#define XS { OP_XS, v_mode } +#define EMC { OP_EMC, v_mode } +#define MXC { OP_MXC, 0 } +#define VM { OP_VMX, q_mode } +#define OPSUF { OP_3DNowSuffix, 0 } +#define OPSIMD { OP_SIMD_Suffix, 0 } +#define XMM0 { XMM_Fixup, 0 } + +/* Used handle "rep" prefix for string instructions. */ +#define Xbr { REP_Fixup, eSI_reg } +#define Xvr { REP_Fixup, eSI_reg } +#define Ybr { REP_Fixup, eDI_reg } +#define Yvr { REP_Fixup, eDI_reg } +#define Yzr { REP_Fixup, eDI_reg } +#define indirDXr { REP_Fixup, indir_dx_reg } +#define ALr { REP_Fixup, al_reg } +#define eAXr { REP_Fixup, eAX_reg } + +#define cond_jump_flag { NULL, cond_jump_mode } +#define loop_jcxz_flag { NULL, loop_jcxz_mode } + +/* bits in sizeflag */ +#define SUFFIX_ALWAYS 4 +#define AFLAG 2 +#define DFLAG 1 + +#define b_mode 1 /* byte operand */ +#define v_mode 2 /* operand size depends on prefixes */ +#define w_mode 3 /* word operand */ +#define d_mode 4 /* double word operand */ +#define q_mode 5 /* quad word operand */ +#define t_mode 6 /* ten-byte operand */ +#define x_mode 7 /* 16-byte XMM operand */ +#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ +#define cond_jump_mode 9 +#define loop_jcxz_mode 10 +#define dq_mode 11 /* operand size depends on REX prefixes. */ +#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ +#define f_mode 13 /* 4- or 6-byte pointer operand */ +#define const_1_mode 14 +#define stack_v_mode 15 /* v_mode for stack-related opcodes. */ +#define z_mode 16 /* non-quad operand size depends on prefixes */ +#define o_mode 17 /* 16-byte operand */ +#define dqb_mode 18 /* registers like dq_mode, memory like b_mode. */ +#define dqd_mode 19 /* registers like dq_mode, memory like d_mode. */ + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 + +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define rAX_reg 132 +#define rCX_reg 133 +#define rDX_reg 134 +#define rBX_reg 135 +#define rSP_reg 136 +#define rBP_reg 137 +#define rSI_reg 138 +#define rDI_reg 139 + +#define z_mode_ax_reg 149 +#define indir_dx_reg 150 + +#define FLOATCODE 1 +#define USE_GROUPS 2 +#define USE_PREFIX_USER_TABLE 3 +#define X86_64_SPECIAL 4 +#define IS_3BYTE_OPCODE 5 + +#define FLOAT NULL, { { NULL, FLOATCODE } } + +#define GRP1a NULL, { { NULL, USE_GROUPS }, { NULL, 0 } } +#define GRP1b NULL, { { NULL, USE_GROUPS }, { NULL, 1 } } +#define GRP1S NULL, { { NULL, USE_GROUPS }, { NULL, 2 } } +#define GRP1Ss NULL, { { NULL, USE_GROUPS }, { NULL, 3 } } +#define GRP2b NULL, { { NULL, USE_GROUPS }, { NULL, 4 } } +#define GRP2S NULL, { { NULL, USE_GROUPS }, { NULL, 5 } } +#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL, 6 } } +#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL, 7 } } +#define GRP2b_cl NULL, { { NULL, USE_GROUPS }, { NULL, 8 } } +#define GRP2S_cl NULL, { { NULL, USE_GROUPS }, { NULL, 9 } } +#define GRP3b NULL, { { NULL, USE_GROUPS }, { NULL, 10 } } +#define GRP3S NULL, { { NULL, USE_GROUPS }, { NULL, 11 } } +#define GRP4 NULL, { { NULL, USE_GROUPS }, { NULL, 12 } } +#define GRP5 NULL, { { NULL, USE_GROUPS }, { NULL, 13 } } +#define GRP6 NULL, { { NULL, USE_GROUPS }, { NULL, 14 } } +#define GRP7 NULL, { { NULL, USE_GROUPS }, { NULL, 15 } } +#define GRP8 NULL, { { NULL, USE_GROUPS }, { NULL, 16 } } +#define GRP9 NULL, { { NULL, USE_GROUPS }, { NULL, 17 } } +#define GRP11_C6 NULL, { { NULL, USE_GROUPS }, { NULL, 18 } } +#define GRP11_C7 NULL, { { NULL, USE_GROUPS }, { NULL, 19 } } +#define GRP12 NULL, { { NULL, USE_GROUPS }, { NULL, 20 } } +#define GRP13 NULL, { { NULL, USE_GROUPS }, { NULL, 21 } } +#define GRP14 NULL, { { NULL, USE_GROUPS }, { NULL, 22 } } +#define GRP15 NULL, { { NULL, USE_GROUPS }, { NULL, 23 } } +#define GRP16 NULL, { { NULL, USE_GROUPS }, { NULL, 24 } } +#define GRPAMD NULL, { { NULL, USE_GROUPS }, { NULL, 25 } } +#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } } +#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } } + +#define PREGRP0 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 0 } } +#define PREGRP1 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 1 } } +#define PREGRP2 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 2 } } +#define PREGRP3 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 3 } } +#define PREGRP4 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 4 } } +#define PREGRP5 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 5 } } +#define PREGRP6 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 6 } } +#define PREGRP7 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 7 } } +#define PREGRP8 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 8 } } +#define PREGRP9 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 9 } } +#define PREGRP10 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } } +#define PREGRP11 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } } +#define PREGRP12 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } } +#define PREGRP13 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } } +#define PREGRP14 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } } +#define PREGRP15 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } } +#define PREGRP16 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } } +#define PREGRP17 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } } +#define PREGRP18 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } } +#define PREGRP19 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } } +#define PREGRP20 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } } +#define PREGRP21 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } } +#define PREGRP22 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } } +#define PREGRP23 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } } +#define PREGRP24 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } } +#define PREGRP25 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } } +#define PREGRP26 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } } +#define PREGRP27 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } } +#define PREGRP28 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } } +#define PREGRP29 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } } +#define PREGRP30 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } } +#define PREGRP31 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } } +#define PREGRP32 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } } +#define PREGRP33 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } } +#define PREGRP34 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } } +#define PREGRP35 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } } +#define PREGRP36 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } } +#define PREGRP37 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } } +#define PREGRP38 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } } +#define PREGRP39 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } } +#define PREGRP40 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } } +#define PREGRP41 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } } +#define PREGRP42 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } } +#define PREGRP43 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } } +#define PREGRP44 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } } +#define PREGRP45 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } } +#define PREGRP46 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } } +#define PREGRP47 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } } +#define PREGRP48 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } } +#define PREGRP49 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } } +#define PREGRP50 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } } +#define PREGRP51 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } } +#define PREGRP52 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } } +#define PREGRP53 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } } +#define PREGRP54 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } } +#define PREGRP55 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } } +#define PREGRP56 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } } +#define PREGRP57 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } } +#define PREGRP58 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } } +#define PREGRP59 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } } +#define PREGRP60 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } } +#define PREGRP61 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } } +#define PREGRP62 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } } +#define PREGRP63 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } } +#define PREGRP64 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } } +#define PREGRP65 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } } +#define PREGRP66 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } } +#define PREGRP67 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } } +#define PREGRP68 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } } +#define PREGRP69 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } } +#define PREGRP70 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } } +#define PREGRP71 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } } +#define PREGRP72 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } } +#define PREGRP73 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } } +#define PREGRP74 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } } +#define PREGRP75 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } } +#define PREGRP76 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } } +#define PREGRP77 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } } +#define PREGRP78 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } } +#define PREGRP79 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } } +#define PREGRP80 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } } +#define PREGRP81 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } } +#define PREGRP82 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } } +#define PREGRP83 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } } +#define PREGRP84 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } } +#define PREGRP85 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } } +#define PREGRP86 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } } +#define PREGRP87 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } } +#define PREGRP88 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } } +#define PREGRP89 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } } +#define PREGRP90 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } } +#define PREGRP91 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } } +#define PREGRP92 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } } +#define PREGRP93 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } } +#define PREGRP94 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } } +#define PREGRP95 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } } +#define PREGRP96 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } } +#define PREGRP97 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } } + + +#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } } +#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } } +#define X86_64_2 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } } +#define X86_64_3 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } } + +#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } } +#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } } + +typedef void (*op_rtn) (int bytemode, int sizeflag); + +struct dis386 { + const char *name; + struct + { + op_rtn rtn; + int bytemode; + } op[MAX_OPERANDS]; +}; + +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand + . size prefix + 'D' => print 'w' if no register operands or 'w', 'l' or 'q', if + . suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'F' => print 'w' or 'l' depending on address size prefix (loop insns) + 'G' => print 'w' or 'l' depending on operand size prefix (i/o insns) + 'H' => print ",pt" or ",pn" branch hint + 'I' => honor following macro letter even in Intel mode (implemented only + . for some of the macro letters) + 'J' => print 'l' + 'K' => print 'd' or 'q' if rex prefix is present. + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'O' => print 'd' or 'o' (or 'q' in Intel mode) + 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true + 'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode) + 'S' => print 'w', 'l' or 'q' if suffix_always is true + 'T' => print 'q' in 64bit mode and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise + 'V' => print 'q' in 64bit mode and behave as 'S' otherwise + 'W' => print 'b', 'w' or 'l' ('d' in Intel mode) + 'X' => print 's', 'd' depending on data16 prefix (for XMM) + 'Y' => 'q' if instruction has an REX 64bit overwrite prefix + 'Z' => print 'q' in 64bit mode and behave as 'L' otherwise + + Many of the above letters print nothing in Intel mode. See "putop" + for the details. + + Braces '{' and '}', and vertical bars '|', indicate alternative + mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel + modes. In cases where there are only two alternatives, the X86_64 + instruction is reserved, and "(bad)" is printed. +*/ + +static const struct dis386 dis386[] = { + /* 00 */ + { "addB", { Eb, Gb } }, + { "addS", { Ev, Gv } }, + { "addB", { Gb, Eb } }, + { "addS", { Gv, Ev } }, + { "addB", { AL, Ib } }, + { "addS", { eAX, Iv } }, + { "push{T|}", { es } }, + { "pop{T|}", { es } }, + /* 08 */ + { "orB", { Eb, Gb } }, + { "orS", { Ev, Gv } }, + { "orB", { Gb, Eb } }, + { "orS", { Gv, Ev } }, + { "orB", { AL, Ib } }, + { "orS", { eAX, Iv } }, + { "push{T|}", { cs } }, + { "(bad)", { XX } }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcB", { Eb, Gb } }, + { "adcS", { Ev, Gv } }, + { "adcB", { Gb, Eb } }, + { "adcS", { Gv, Ev } }, + { "adcB", { AL, Ib } }, + { "adcS", { eAX, Iv } }, + { "push{T|}", { ss } }, + { "pop{T|}", { ss } }, + /* 18 */ + { "sbbB", { Eb, Gb } }, + { "sbbS", { Ev, Gv } }, + { "sbbB", { Gb, Eb } }, + { "sbbS", { Gv, Ev } }, + { "sbbB", { AL, Ib } }, + { "sbbS", { eAX, Iv } }, + { "push{T|}", { ds } }, + { "pop{T|}", { ds } }, + /* 20 */ + { "andB", { Eb, Gb } }, + { "andS", { Ev, Gv } }, + { "andB", { Gb, Eb } }, + { "andS", { Gv, Ev } }, + { "andB", { AL, Ib } }, + { "andS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG ES prefix */ + { "daa{|}", { XX } }, + /* 28 */ + { "subB", { Eb, Gb } }, + { "subS", { Ev, Gv } }, + { "subB", { Gb, Eb } }, + { "subS", { Gv, Ev } }, + { "subB", { AL, Ib } }, + { "subS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG CS prefix */ + { "das{|}", { XX } }, + /* 30 */ + { "xorB", { Eb, Gb } }, + { "xorS", { Ev, Gv } }, + { "xorB", { Gb, Eb } }, + { "xorS", { Gv, Ev } }, + { "xorB", { AL, Ib } }, + { "xorS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG SS prefix */ + { "aaa{|}", { XX } }, + /* 38 */ + { "cmpB", { Eb, Gb } }, + { "cmpS", { Ev, Gv } }, + { "cmpB", { Gb, Eb } }, + { "cmpS", { Gv, Ev } }, + { "cmpB", { AL, Ib } }, + { "cmpS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG DS prefix */ + { "aas{|}", { XX } }, + /* 40 */ + { "inc{S|}", { RMeAX } }, + { "inc{S|}", { RMeCX } }, + { "inc{S|}", { RMeDX } }, + { "inc{S|}", { RMeBX } }, + { "inc{S|}", { RMeSP } }, + { "inc{S|}", { RMeBP } }, + { "inc{S|}", { RMeSI } }, + { "inc{S|}", { RMeDI } }, + /* 48 */ + { "dec{S|}", { RMeAX } }, + { "dec{S|}", { RMeCX } }, + { "dec{S|}", { RMeDX } }, + { "dec{S|}", { RMeBX } }, + { "dec{S|}", { RMeSP } }, + { "dec{S|}", { RMeBP } }, + { "dec{S|}", { RMeSI } }, + { "dec{S|}", { RMeDI } }, + /* 50 */ + { "pushV", { RMrAX } }, + { "pushV", { RMrCX } }, + { "pushV", { RMrDX } }, + { "pushV", { RMrBX } }, + { "pushV", { RMrSP } }, + { "pushV", { RMrBP } }, + { "pushV", { RMrSI } }, + { "pushV", { RMrDI } }, + /* 58 */ + { "popV", { RMrAX } }, + { "popV", { RMrCX } }, + { "popV", { RMrDX } }, + { "popV", { RMrBX } }, + { "popV", { RMrSP } }, + { "popV", { RMrBP } }, + { "popV", { RMrSI } }, + { "popV", { RMrDI } }, + /* 60 */ + { X86_64_0 }, + { X86_64_1 }, + { X86_64_2 }, + { X86_64_3 }, + { "(bad)", { XX } }, /* seg fs */ + { "(bad)", { XX } }, /* seg gs */ + { "(bad)", { XX } }, /* op size prefix */ + { "(bad)", { XX } }, /* adr size prefix */ + /* 68 */ + { "pushT", { Iq } }, + { "imulS", { Gv, Ev, Iv } }, + { "pushT", { sIb } }, + { "imulS", { Gv, Ev, sIb } }, + { "ins{b||b|}", { Ybr, indirDX } }, + { "ins{R||G|}", { Yzr, indirDX } }, + { "outs{b||b|}", { indirDXr, Xb } }, + { "outs{R||G|}", { indirDXr, Xz } }, + /* 70 */ + { "joH", { Jb, XX, cond_jump_flag } }, + { "jnoH", { Jb, XX, cond_jump_flag } }, + { "jbH", { Jb, XX, cond_jump_flag } }, + { "jaeH", { Jb, XX, cond_jump_flag } }, + { "jeH", { Jb, XX, cond_jump_flag } }, + { "jneH", { Jb, XX, cond_jump_flag } }, + { "jbeH", { Jb, XX, cond_jump_flag } }, + { "jaH", { Jb, XX, cond_jump_flag } }, + /* 78 */ + { "jsH", { Jb, XX, cond_jump_flag } }, + { "jnsH", { Jb, XX, cond_jump_flag } }, + { "jpH", { Jb, XX, cond_jump_flag } }, + { "jnpH", { Jb, XX, cond_jump_flag } }, + { "jlH", { Jb, XX, cond_jump_flag } }, + { "jgeH", { Jb, XX, cond_jump_flag } }, + { "jleH", { Jb, XX, cond_jump_flag } }, + { "jgH", { Jb, XX, cond_jump_flag } }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", { XX } }, + { GRP1Ss }, + { "testB", { Eb, Gb } }, + { "testS", { Ev, Gv } }, + { "xchgB", { Eb, Gb } }, + { "xchgS", { Ev, Gv } }, + /* 88 */ + { "movB", { Eb, Gb } }, + { "movS", { Ev, Gv } }, + { "movB", { Gb, Eb } }, + { "movS", { Gv, Ev } }, + { "movD", { Sv, Sw } }, + { "leaS", { Gv, M } }, + { "movD", { Sw, Sv } }, + { GRP1a }, + /* 90 */ + { PREGRP38 }, + { "xchgS", { RMeCX, eAX } }, + { "xchgS", { RMeDX, eAX } }, + { "xchgS", { RMeBX, eAX } }, + { "xchgS", { RMeSP, eAX } }, + { "xchgS", { RMeBP, eAX } }, + { "xchgS", { RMeSI, eAX } }, + { "xchgS", { RMeDI, eAX } }, + /* 98 */ + { "cW{t||t|}R", { XX } }, + { "cR{t||t|}O", { XX } }, + { "Jcall{T|}", { Ap } }, + { "(bad)", { XX } }, /* fwait */ + { "pushfT", { XX } }, + { "popfT", { XX } }, + { "sahf{|}", { XX } }, + { "lahf{|}", { XX } }, + /* a0 */ + { "movB", { AL, Ob } }, + { "movS", { eAX, Ov } }, + { "movB", { Ob, AL } }, + { "movS", { Ov, eAX } }, + { "movs{b||b|}", { Ybr, Xb } }, + { "movs{R||R|}", { Yvr, Xv } }, + { "cmps{b||b|}", { Xb, Yb } }, + { "cmps{R||R|}", { Xv, Yv } }, + /* a8 */ + { "testB", { AL, Ib } }, + { "testS", { eAX, Iv } }, + { "stosB", { Ybr, AL } }, + { "stosS", { Yvr, eAX } }, + { "lodsB", { ALr, Xb } }, + { "lodsS", { eAXr, Xv } }, + { "scasB", { AL, Yb } }, + { "scasS", { eAX, Yv } }, + /* b0 */ + { "movB", { RMAL, Ib } }, + { "movB", { RMCL, Ib } }, + { "movB", { RMDL, Ib } }, + { "movB", { RMBL, Ib } }, + { "movB", { RMAH, Ib } }, + { "movB", { RMCH, Ib } }, + { "movB", { RMDH, Ib } }, + { "movB", { RMBH, Ib } }, + /* b8 */ + { "movS", { RMeAX, Iv64 } }, + { "movS", { RMeCX, Iv64 } }, + { "movS", { RMeDX, Iv64 } }, + { "movS", { RMeBX, Iv64 } }, + { "movS", { RMeSP, Iv64 } }, + { "movS", { RMeBP, Iv64 } }, + { "movS", { RMeSI, Iv64 } }, + { "movS", { RMeDI, Iv64 } }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "retT", { Iw } }, + { "retT", { XX } }, + { "les{S|}", { Gv, Mp } }, + { "ldsS", { Gv, Mp } }, + { GRP11_C6 }, + { GRP11_C7 }, + /* c8 */ + { "enterT", { Iw, Ib } }, + { "leaveT", { XX } }, + { "lretP", { Iw } }, + { "lretP", { XX } }, + { "int3", { XX } }, + { "int", { Ib } }, + { "into{|}", { XX } }, + { "iretP", { XX } }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam{|}", { sIb } }, + { "aad{|}", { sIb } }, + { "(bad)", { XX } }, + { "xlat", { DSBX } }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopneFH", { Jb, XX, loop_jcxz_flag } }, + { "loopeFH", { Jb, XX, loop_jcxz_flag } }, + { "loopFH", { Jb, XX, loop_jcxz_flag } }, + { "jEcxzH", { Jb, XX, loop_jcxz_flag } }, + { "inB", { AL, Ib } }, + { "inG", { zAX, Ib } }, + { "outB", { Ib, AL } }, + { "outG", { Ib, zAX } }, + /* e8 */ + { "callT", { Jv } }, + { "jmpT", { Jv } }, + { "Jjmp{T|}", { Ap } }, + { "jmp", { Jb } }, + { "inB", { AL, indirDX } }, + { "inG", { zAX, indirDX } }, + { "outB", { indirDX, AL } }, + { "outG", { indirDX, zAX } }, + /* f0 */ + { "(bad)", { XX } }, /* lock prefix */ + { "icebp", { XX } }, + { "(bad)", { XX } }, /* repne */ + { "(bad)", { XX } }, /* repz */ + { "hlt", { XX } }, + { "cmc", { XX } }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", { XX } }, + { "stc", { XX } }, + { "cli", { XX } }, + { "sti", { XX } }, + { "cld", { XX } }, + { "std", { XX } }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", { Gv, Ew } }, + { "lslS", { Gv, Ew } }, + { "(bad)", { XX } }, + { "syscall", { XX } }, + { "clts", { XX } }, + { "sysretP", { XX } }, + /* 08 */ + { "invd", { XX } }, + { "wbinvd", { XX } }, + { "(bad)", { XX } }, + { "ud2a", { XX } }, + { "(bad)", { XX } }, + { GRPAMD }, + { "femms", { XX } }, + { "", { MX, EM, OPSUF } }, /* See OP_3DNowSuffix. */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { PREGRP30 }, + { "movlpX", { EXq, XM, { SIMD_Fixup, 'h' } } }, + { "unpcklpX", { XM, EXq } }, + { "unpckhpX", { XM, EXq } }, + { PREGRP31 }, + { "movhpX", { EXq, XM, { SIMD_Fixup, 'l' } } }, + /* 18 */ + { GRP16 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "nopQ", { Ev } }, + /* 20 */ + { "movZ", { Rm, Cm } }, + { "movZ", { Rm, Dm } }, + { "movZ", { Cm, Rm } }, + { "movZ", { Dm, Rm } }, + { "movL", { Rd, Td } }, + { "(bad)", { XX } }, + { "movL", { Td, Rd } }, + { "(bad)", { XX } }, + /* 28 */ + { "movapX", { XM, EXx } }, + { "movapX", { EXx, XM } }, + { PREGRP2 }, + { PREGRP33 }, + { PREGRP4 }, + { PREGRP3 }, + { PREGRP93 }, + { PREGRP94 }, + /* 30 */ + { "wrmsr", { XX } }, + { "rdtsc", { XX } }, + { "rdmsr", { XX } }, + { "rdpmc", { XX } }, + { "sysenter", { XX } }, + { "sysexit", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 38 */ + { THREE_BYTE_0 }, + { "(bad)", { XX } }, + { THREE_BYTE_1 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 40 */ + { "cmovo", { Gv, Ev } }, + { "cmovno", { Gv, Ev } }, + { "cmovb", { Gv, Ev } }, + { "cmovae", { Gv, Ev } }, + { "cmove", { Gv, Ev } }, + { "cmovne", { Gv, Ev } }, + { "cmovbe", { Gv, Ev } }, + { "cmova", { Gv, Ev } }, + /* 48 */ + { "cmovs", { Gv, Ev } }, + { "cmovns", { Gv, Ev } }, + { "cmovp", { Gv, Ev } }, + { "cmovnp", { Gv, Ev } }, + { "cmovl", { Gv, Ev } }, + { "cmovge", { Gv, Ev } }, + { "cmovle", { Gv, Ev } }, + { "cmovg", { Gv, Ev } }, + /* 50 */ + { "movmskpX", { Gdq, XS } }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andpX", { XM, EXx } }, + { "andnpX", { XM, EXx } }, + { "orpX", { XM, EXx } }, + { "xorpX", { XM, EXx } }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { PREGRP17 }, + { PREGRP16 }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { PREGRP95 }, + { PREGRP96 }, + { PREGRP97 }, + { "packsswb", { MX, EM } }, + { "pcmpgtb", { MX, EM } }, + { "pcmpgtw", { MX, EM } }, + { "pcmpgtd", { MX, EM } }, + { "packuswb", { MX, EM } }, + /* 68 */ + { "punpckhbw", { MX, EM } }, + { "punpckhwd", { MX, EM } }, + { "punpckhdq", { MX, EM } }, + { "packssdw", { MX, EM } }, + { PREGRP26 }, + { PREGRP24 }, + { "movd", { MX, Edq } }, + { PREGRP19 }, + /* 70 */ + { PREGRP22 }, + { GRP12 }, + { GRP13 }, + { GRP14 }, + { "pcmpeqb", { MX, EM } }, + { "pcmpeqw", { MX, EM } }, + { "pcmpeqd", { MX, EM } }, + { "emms", { XX } }, + /* 78 */ + { PREGRP34 }, + { PREGRP35 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP28 }, + { PREGRP29 }, + { PREGRP23 }, + { PREGRP20 }, + /* 80 */ + { "joH", { Jv, XX, cond_jump_flag } }, + { "jnoH", { Jv, XX, cond_jump_flag } }, + { "jbH", { Jv, XX, cond_jump_flag } }, + { "jaeH", { Jv, XX, cond_jump_flag } }, + { "jeH", { Jv, XX, cond_jump_flag } }, + { "jneH", { Jv, XX, cond_jump_flag } }, + { "jbeH", { Jv, XX, cond_jump_flag } }, + { "jaH", { Jv, XX, cond_jump_flag } }, + /* 88 */ + { "jsH", { Jv, XX, cond_jump_flag } }, + { "jnsH", { Jv, XX, cond_jump_flag } }, + { "jpH", { Jv, XX, cond_jump_flag } }, + { "jnpH", { Jv, XX, cond_jump_flag } }, + { "jlH", { Jv, XX, cond_jump_flag } }, + { "jgeH", { Jv, XX, cond_jump_flag } }, + { "jleH", { Jv, XX, cond_jump_flag } }, + { "jgH", { Jv, XX, cond_jump_flag } }, + /* 90 */ + { "seto", { Eb } }, + { "setno", { Eb } }, + { "setb", { Eb } }, + { "setae", { Eb } }, + { "sete", { Eb } }, + { "setne", { Eb } }, + { "setbe", { Eb } }, + { "seta", { Eb } }, + /* 98 */ + { "sets", { Eb } }, + { "setns", { Eb } }, + { "setp", { Eb } }, + { "setnp", { Eb } }, + { "setl", { Eb } }, + { "setge", { Eb } }, + { "setle", { Eb } }, + { "setg", { Eb } }, + /* a0 */ + { "pushT", { fs } }, + { "popT", { fs } }, + { "cpuid", { XX } }, + { "btS", { Ev, Gv } }, + { "shldS", { Ev, Gv, Ib } }, + { "shldS", { Ev, Gv, CL } }, + { GRPPADLCK2 }, + { GRPPADLCK1 }, + /* a8 */ + { "pushT", { gs } }, + { "popT", { gs } }, + { "rsm", { XX } }, + { "btsS", { Ev, Gv } }, + { "shrdS", { Ev, Gv, Ib } }, + { "shrdS", { Ev, Gv, CL } }, + { GRP15 }, + { "imulS", { Gv, Ev } }, + /* b0 */ + { "cmpxchgB", { Eb, Gb } }, + { "cmpxchgS", { Ev, Gv } }, + { "lssS", { Gv, Mp } }, + { "btrS", { Ev, Gv } }, + { "lfsS", { Gv, Mp } }, + { "lgsS", { Gv, Mp } }, + { "movz{bR|x|bR|x}", { Gv, Eb } }, + { "movz{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movzww ! */ + /* b8 */ + { PREGRP37 }, + { "ud2b", { XX } }, + { GRP8 }, + { "btcS", { Ev, Gv } }, + { "bsfS", { Gv, Ev } }, + { PREGRP36 }, + { "movs{bR|x|bR|x}", { Gv, Eb } }, + { "movs{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movsww ! */ + /* c0 */ + { "xaddB", { Eb, Gb } }, + { "xaddS", { Ev, Gv } }, + { PREGRP1 }, + { "movntiS", { Ev, Gv } }, + { "pinsrw", { MX, Edqw, Ib } }, + { "pextrw", { Gdq, MS, Ib } }, + { "shufpX", { XM, EXx, Ib } }, + { GRP9 }, + /* c8 */ + { "bswap", { RMeAX } }, + { "bswap", { RMeCX } }, + { "bswap", { RMeDX } }, + { "bswap", { RMeBX } }, + { "bswap", { RMeSP } }, + { "bswap", { RMeBP } }, + { "bswap", { RMeSI } }, + { "bswap", { RMeDI } }, + /* d0 */ + { PREGRP27 }, + { "psrlw", { MX, EM } }, + { "psrld", { MX, EM } }, + { "psrlq", { MX, EM } }, + { "paddq", { MX, EM } }, + { "pmullw", { MX, EM } }, + { PREGRP21 }, + { "pmovmskb", { Gdq, MS } }, + /* d8 */ + { "psubusb", { MX, EM } }, + { "psubusw", { MX, EM } }, + { "pminub", { MX, EM } }, + { "pand", { MX, EM } }, + { "paddusb", { MX, EM } }, + { "paddusw", { MX, EM } }, + { "pmaxub", { MX, EM } }, + { "pandn", { MX, EM } }, + /* e0 */ + { "pavgb", { MX, EM } }, + { "psraw", { MX, EM } }, + { "psrad", { MX, EM } }, + { "pavgw", { MX, EM } }, + { "pmulhuw", { MX, EM } }, + { "pmulhw", { MX, EM } }, + { PREGRP15 }, + { PREGRP25 }, + /* e8 */ + { "psubsb", { MX, EM } }, + { "psubsw", { MX, EM } }, + { "pminsw", { MX, EM } }, + { "por", { MX, EM } }, + { "paddsb", { MX, EM } }, + { "paddsw", { MX, EM } }, + { "pmaxsw", { MX, EM } }, + { "pxor", { MX, EM } }, + /* f0 */ + { PREGRP32 }, + { "psllw", { MX, EM } }, + { "pslld", { MX, EM } }, + { "psllq", { MX, EM } }, + { "pmuludq", { MX, EM } }, + { "pmaddwd", { MX, EM } }, + { "psadbw", { MX, EM } }, + { PREGRP18 }, + /* f8 */ + { "psubb", { MX, EM } }, + { "psubw", { MX, EM } }, + { "psubd", { MX, EM } }, + { "psubq", { MX, EM } }, + { "paddb", { MX, EM } }, + { "paddw", { MX, EM } }, + { "paddd", { MX, EM } }, + { "(bad)", { XX } }, +}; + +static const unsigned char onebyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */ + /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses DATA prefix. */ +static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */ + /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */ + /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */ + /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix. */ +static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses REPZ prefix. */ +static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses DATA prefix. */ +static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */ + /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix. */ +static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses REPZ prefix. */ +static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *insn_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static struct + { + int mod; + int reg; + int rm; + } +modrm; +static unsigned char need_modrm; + +/* If we are accessing mod/rm/reg without need_modrm set, then the + values are stale. Hitting this abort likely indicates that you + need to update onebyte_has_modrm or twobyte_has_modrm. */ +#define MODRM_CHECK if (!need_modrm) abort () + +static const char * const *names64; +static const char * const *names32; +static const char * const *names16; +static const char * const *names8; +static const char * const *names8rex; +static const char * const *names_seg; +static const char * const *index16; + +static const char * const intel_names64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; +static const char * const intel_names32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" +}; +static const char * const intel_names16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" +}; +static const char * const intel_names8[] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", +}; +static const char * const intel_names8rex[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" +}; +static const char * const intel_names_seg[] = { + "es", "cs", "ss", "ds", "fs", "gs", "?", "?", +}; +static const char * const intel_index16[] = { + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" +}; + +static const char * const att_names64[] = { + "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +}; +static const char * const att_names32[] = { + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" +}; +static const char * const att_names16[] = { + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" +}; +static const char * const att_names8[] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", +}; +static const char * const att_names8rex[] = { + "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" +}; +static const char * const att_names_seg[] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", +}; +static const char * const att_index16[] = { + "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" +}; + +static const struct dis386 grps[][8] = { + /* GRP1a */ + { + { "popU", { stackEv } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP1b */ + { + { "addA", { Eb, Ib } }, + { "orA", { Eb, Ib } }, + { "adcA", { Eb, Ib } }, + { "sbbA", { Eb, Ib } }, + { "andA", { Eb, Ib } }, + { "subA", { Eb, Ib } }, + { "xorA", { Eb, Ib } }, + { "cmpA", { Eb, Ib } }, + }, + /* GRP1S */ + { + { "addQ", { Ev, Iv } }, + { "orQ", { Ev, Iv } }, + { "adcQ", { Ev, Iv } }, + { "sbbQ", { Ev, Iv } }, + { "andQ", { Ev, Iv } }, + { "subQ", { Ev, Iv } }, + { "xorQ", { Ev, Iv } }, + { "cmpQ", { Ev, Iv } }, + }, + /* GRP1Ss */ + { + { "addQ", { Ev, sIb } }, + { "orQ", { Ev, sIb } }, + { "adcQ", { Ev, sIb } }, + { "sbbQ", { Ev, sIb } }, + { "andQ", { Ev, sIb } }, + { "subQ", { Ev, sIb } }, + { "xorQ", { Ev, sIb } }, + { "cmpQ", { Ev, sIb } }, + }, + /* GRP2b */ + { + { "rolA", { Eb, Ib } }, + { "rorA", { Eb, Ib } }, + { "rclA", { Eb, Ib } }, + { "rcrA", { Eb, Ib } }, + { "shlA", { Eb, Ib } }, + { "shrA", { Eb, Ib } }, + { "(bad)", { XX } }, + { "sarA", { Eb, Ib } }, + }, + /* GRP2S */ + { + { "rolQ", { Ev, Ib } }, + { "rorQ", { Ev, Ib } }, + { "rclQ", { Ev, Ib } }, + { "rcrQ", { Ev, Ib } }, + { "shlQ", { Ev, Ib } }, + { "shrQ", { Ev, Ib } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, Ib } }, + }, + /* GRP2b_one */ + { + { "rolA", { Eb, I1 } }, + { "rorA", { Eb, I1 } }, + { "rclA", { Eb, I1 } }, + { "rcrA", { Eb, I1 } }, + { "shlA", { Eb, I1 } }, + { "shrA", { Eb, I1 } }, + { "(bad)", { XX } }, + { "sarA", { Eb, I1 } }, + }, + /* GRP2S_one */ + { + { "rolQ", { Ev, I1 } }, + { "rorQ", { Ev, I1 } }, + { "rclQ", { Ev, I1 } }, + { "rcrQ", { Ev, I1 } }, + { "shlQ", { Ev, I1 } }, + { "shrQ", { Ev, I1 } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, I1 } }, + }, + /* GRP2b_cl */ + { + { "rolA", { Eb, CL } }, + { "rorA", { Eb, CL } }, + { "rclA", { Eb, CL } }, + { "rcrA", { Eb, CL } }, + { "shlA", { Eb, CL } }, + { "shrA", { Eb, CL } }, + { "(bad)", { XX } }, + { "sarA", { Eb, CL } }, + }, + /* GRP2S_cl */ + { + { "rolQ", { Ev, CL } }, + { "rorQ", { Ev, CL } }, + { "rclQ", { Ev, CL } }, + { "rcrQ", { Ev, CL } }, + { "shlQ", { Ev, CL } }, + { "shrQ", { Ev, CL } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, CL } }, + }, + /* GRP3b */ + { + { "testA", { Eb, Ib } }, + { "(bad)", { Eb } }, + { "notA", { Eb } }, + { "negA", { Eb } }, + { "mulA", { Eb } }, /* Don't print the implicit %al register, */ + { "imulA", { Eb } }, /* to distinguish these opcodes from other */ + { "divA", { Eb } }, /* mul/imul opcodes. Do the same for div */ + { "idivA", { Eb } }, /* and idiv for consistency. */ + }, + /* GRP3S */ + { + { "testQ", { Ev, Iv } }, + { "(bad)", { XX } }, + { "notQ", { Ev } }, + { "negQ", { Ev } }, + { "mulQ", { Ev } }, /* Don't print the implicit register. */ + { "imulQ", { Ev } }, + { "divQ", { Ev } }, + { "idivQ", { Ev } }, + }, + /* GRP4 */ + { + { "incA", { Eb } }, + { "decA", { Eb } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP5 */ + { + { "incQ", { Ev } }, + { "decQ", { Ev } }, + { "callT", { indirEv } }, + { "JcallT", { indirEp } }, + { "jmpT", { indirEv } }, + { "JjmpT", { indirEp } }, + { "pushU", { stackEv } }, + { "(bad)", { XX } }, + }, + /* GRP6 */ + { + { "sldtD", { Sv } }, + { "strD", { Sv } }, + { "lldt", { Ew } }, + { "ltr", { Ew } }, + { "verr", { Ew } }, + { "verw", { Ew } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP7 */ + { + { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } }, + { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } }, + { "lgdt{Q|Q||}", { M } }, + { "lidt{Q|Q||}", { { SVME_Fixup, 0 } } }, + { "smswD", { Sv } }, + { "(bad)", { XX } }, + { "lmsw", { Ew } }, + { "invlpg", { { INVLPG_Fixup, w_mode } } }, + }, + /* GRP8 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "btQ", { Ev, Ib } }, + { "btsQ", { Ev, Ib } }, + { "btrQ", { Ev, Ib } }, + { "btcQ", { Ev, Ib } }, + }, + /* GRP9 */ + { + { "(bad)", { XX } }, + { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "", { VM } }, /* See OP_VMX. */ + { "vmptrst", { Mq } }, + }, + /* GRP11_C6 */ + { + { "movA", { Eb, Ib } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP11_C7 */ + { + { "movQ", { Ev, Iv } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP12 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrlw", { MS, Ib } }, + { "(bad)", { XX } }, + { "psraw", { MS, Ib } }, + { "(bad)", { XX } }, + { "psllw", { MS, Ib } }, + { "(bad)", { XX } }, + }, + /* GRP13 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrld", { MS, Ib } }, + { "(bad)", { XX } }, + { "psrad", { MS, Ib } }, + { "(bad)", { XX } }, + { "pslld", { MS, Ib } }, + { "(bad)", { XX } }, + }, + /* GRP14 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrlq", { MS, Ib } }, + { "psrldq", { MS, Ib } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psllq", { MS, Ib } }, + { "pslldq", { MS, Ib } }, + }, + /* GRP15 */ + { + { "fxsave", { Ev } }, + { "fxrstor", { Ev } }, + { "ldmxcsr", { Ev } }, + { "stmxcsr", { Ev } }, + { "(bad)", { XX } }, + { "lfence", { { OP_0fae, 0 } } }, + { "mfence", { { OP_0fae, 0 } } }, + { "clflush", { { OP_0fae, 0 } } }, + }, + /* GRP16 */ + { + { "prefetchnta", { Ev } }, + { "prefetcht0", { Ev } }, + { "prefetcht1", { Ev } }, + { "prefetcht2", { Ev } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRPAMD */ + { + { "prefetch", { Eb } }, + { "prefetchw", { Eb } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRPPADLCK1 */ + { + { "xstore-rng", { { OP_0f07, 0 } } }, + { "xcrypt-ecb", { { OP_0f07, 0 } } }, + { "xcrypt-cbc", { { OP_0f07, 0 } } }, + { "xcrypt-ctr", { { OP_0f07, 0 } } }, + { "xcrypt-cfb", { { OP_0f07, 0 } } }, + { "xcrypt-ofb", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + }, + /* GRPPADLCK2 */ + { + { "montmul", { { OP_0f07, 0 } } }, + { "xsha1", { { OP_0f07, 0 } } }, + { "xsha256", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + } +}; + +static const struct dis386 prefix_user_table[][4] = { + /* PREGRP0 */ + { + { "addps", { XM, EXx } }, + { "addss", { XM, EXd } }, + { "addpd", { XM, EXx } }, + { "addsd", { XM, EXq } }, + }, + /* PREGRP1 */ + { + { "", { XM, EXx, OPSIMD } }, /* See OP_SIMD_SUFFIX. */ + { "", { XM, EXx, OPSIMD } }, + { "", { XM, EXx, OPSIMD } }, + { "", { XM, EXx, OPSIMD } }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", { XM, EMC } }, + { "cvtsi2ssY", { XM, Ev } }, + { "cvtpi2pd", { XM, EMC } }, + { "cvtsi2sdY", { XM, Ev } }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", { MXC, EXx } }, + { "cvtss2siY", { Gv, EXx } }, + { "cvtpd2pi", { MXC, EXx } }, + { "cvtsd2siY", { Gv, EXx } }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", { MXC, EXx } }, + { "cvttss2siY", { Gv, EXx } }, + { "cvttpd2pi", { MXC, EXx } }, + { "cvttsd2siY", { Gv, EXx } }, + }, + /* PREGRP5 */ + { + { "divps", { XM, EXx } }, + { "divss", { XM, EXx } }, + { "divpd", { XM, EXx } }, + { "divsd", { XM, EXx } }, + }, + /* PREGRP6 */ + { + { "maxps", { XM, EXx } }, + { "maxss", { XM, EXx } }, + { "maxpd", { XM, EXx } }, + { "maxsd", { XM, EXx } }, + }, + /* PREGRP7 */ + { + { "minps", { XM, EXx } }, + { "minss", { XM, EXx } }, + { "minpd", { XM, EXx } }, + { "minsd", { XM, EXx } }, + }, + /* PREGRP8 */ + { + { "movups", { XM, EXx } }, + { "movss", { XM, EXx } }, + { "movupd", { XM, EXx } }, + { "movsd", { XM, EXx } }, + }, + /* PREGRP9 */ + { + { "movups", { EXx, XM } }, + { "movss", { EXx, XM } }, + { "movupd", { EXx, XM } }, + { "movsd", { EXx, XM } }, + }, + /* PREGRP10 */ + { + { "mulps", { XM, EXx } }, + { "mulss", { XM, EXx } }, + { "mulpd", { XM, EXx } }, + { "mulsd", { XM, EXx } }, + }, + /* PREGRP11 */ + { + { "rcpps", { XM, EXx } }, + { "rcpss", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP12 */ + { + { "rsqrtps",{ XM, EXx } }, + { "rsqrtss",{ XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP13 */ + { + { "sqrtps", { XM, EXx } }, + { "sqrtss", { XM, EXx } }, + { "sqrtpd", { XM, EXx } }, + { "sqrtsd", { XM, EXx } }, + }, + /* PREGRP14 */ + { + { "subps", { XM, EXx } }, + { "subss", { XM, EXx } }, + { "subpd", { XM, EXx } }, + { "subsd", { XM, EXx } }, + }, + /* PREGRP15 */ + { + { "(bad)", { XM, EXx } }, + { "cvtdq2pd", { XM, EXq } }, + { "cvttpd2dq", { XM, EXx } }, + { "cvtpd2dq", { XM, EXx } }, + }, + /* PREGRP16 */ + { + { "cvtdq2ps", { XM, EXx } }, + { "cvttps2dq", { XM, EXx } }, + { "cvtps2dq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP17 */ + { + { "cvtps2pd", { XM, EXq } }, + { "cvtss2sd", { XM, EXx } }, + { "cvtpd2ps", { XM, EXx } }, + { "cvtsd2ss", { XM, EXx } }, + }, + /* PREGRP18 */ + { + { "maskmovq", { MX, MS } }, + { "(bad)", { XM, EXx } }, + { "maskmovdqu", { XM, XS } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP19 */ + { + { "movq", { MX, EM } }, + { "movdqu", { XM, EXx } }, + { "movdqa", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP20 */ + { + { "movq", { EM, MX } }, + { "movdqu", { EXx, XM } }, + { "movdqa", { EXx, XM } }, + { "(bad)", { EXx, XM } }, + }, + /* PREGRP21 */ + { + { "(bad)", { EXx, XM } }, + { "movq2dq",{ XM, MS } }, + { "movq", { EXx, XM } }, + { "movdq2q",{ MX, XS } }, + }, + /* PREGRP22 */ + { + { "pshufw", { MX, EM, Ib } }, + { "pshufhw",{ XM, EXx, Ib } }, + { "pshufd", { XM, EXx, Ib } }, + { "pshuflw",{ XM, EXx, Ib } }, + }, + /* PREGRP23 */ + { + { "movd", { Edq, MX } }, + { "movq", { XM, EXx } }, + { "movd", { Edq, XM } }, + { "(bad)", { Ed, XM } }, + }, + /* PREGRP24 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "punpckhqdq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP25 */ + { + { "movntq", { EM, MX } }, + { "(bad)", { EM, XM } }, + { "movntdq",{ EM, XM } }, + { "(bad)", { EM, XM } }, + }, + /* PREGRP26 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "punpcklqdq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP27 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "addsubpd", { XM, EXx } }, + { "addsubps", { XM, EXx } }, + }, + /* PREGRP28 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "haddpd", { XM, EXx } }, + { "haddps", { XM, EXx } }, + }, + /* PREGRP29 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "hsubpd", { XM, EXx } }, + { "hsubps", { XM, EXx } }, + }, + /* PREGRP30 */ + { + { "movlpX", { XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */ + { "movsldup", { XM, EXx } }, + { "movlpd", { XM, EXq } }, + { "movddup", { XM, EXq } }, + }, + /* PREGRP31 */ + { + { "movhpX", { XM, EXq, { SIMD_Fixup, 'l' } } }, + { "movshdup", { XM, EXx } }, + { "movhpd", { XM, EXq } }, + { "(bad)", { XM, EXq } }, + }, + /* PREGRP32 */ + { + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "lddqu", { XM, M } }, + }, + /* PREGRP33 */ + { + {"movntps", { Ev, XM } }, + {"movntss", { Ev, XM } }, + {"movntpd", { Ev, XM } }, + {"movntsd", { Ev, XM } }, + }, + + /* PREGRP34 */ + { + {"vmread", { Em, Gm } }, + {"(bad)", { XX } }, + {"extrq", { XS, Ib, Ib } }, + {"insertq", { XM, XS, Ib, Ib } }, + }, + + /* PREGRP35 */ + { + {"vmwrite", { Gm, Em } }, + {"(bad)", { XX } }, + {"extrq", { XM, XS } }, + {"insertq", { XM, XS } }, + }, + + /* PREGRP36 */ + { + { "bsrS", { Gv, Ev } }, + { "lzcntS", { Gv, Ev } }, + { "bsrS", { Gv, Ev } }, + { "(bad)", { XX } }, + }, + + /* PREGRP37 */ + { + { "(bad)", { XX } }, + { "popcntS", { Gv, Ev } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + + /* PREGRP38 */ + { + { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, + { "pause", { XX } }, + { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, + { "(bad)", { XX } }, + }, + + /* PREGRP39 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pblendvb", {XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP40 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendvps", {XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP41 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendvpd", { XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP42 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "ptest", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP43 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP44 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP45 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP46 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxwd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP47 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxwq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP48 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxdq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP49 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmuldq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP50 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpeqq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP51 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "movntdqa", { XM, EM } }, + { "(bad)", { XX } }, + }, + + /* PREGRP52 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "packusdw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP53 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP54 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP55 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP56 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxwd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP57 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxwq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP58 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxdq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP59 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminsb", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP60 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminsd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP61 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP62 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminud", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP63 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxsb", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP64 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxsd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP65 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP66 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxud", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP67 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmulld", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP68 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "phminposuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP69 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP70 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundpd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP71 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundss", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP72 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundsd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP73 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP74 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendpd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP75 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pblendw", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP76 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrb", { Edqb, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP77 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrw", { Edqw, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP78 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrK", { Edq, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP79 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "extractps", { Edqd, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP80 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pinsrb", { XM, Edqb, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP81 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "insertps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP82 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pinsrK", { XM, Edq, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP83 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "dpps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP84 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "dppd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP85 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "mpsadbw", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP86 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpgtq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP87 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "crc32", { Gdq, { CRC32_Fixup, b_mode } } }, + }, + + /* PREGRP88 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "crc32", { Gdq, { CRC32_Fixup, v_mode } } }, + }, + + /* PREGRP89 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpestrm", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP90 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpestri", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP91 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpistrm", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP92 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpistri", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP93 */ + { + { "ucomiss",{ XM, EXd } }, + { "(bad)", { XX } }, + { "ucomisd",{ XM, EXq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP94 */ + { + { "comiss", { XM, EXd } }, + { "(bad)", { XX } }, + { "comisd", { XM, EXq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP95 */ + { + { "punpcklbw",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpcklbw",{ MX, EMq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP96 */ + { + { "punpcklwd",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpcklwd",{ MX, EMq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP97 */ + { + { "punpckldq",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpckldq",{ MX, EMq } }, + { "(bad)", { XX } }, + }, +}; + +static const struct dis386 x86_64_table[][2] = { + { + { "pusha{P|}", { XX } }, + { "(bad)", { XX } }, + }, + { + { "popa{P|}", { XX } }, + { "(bad)", { XX } }, + }, + { + { "bound{S|}", { Gv, Ma } }, + { "(bad)", { XX } }, + }, + { + { "arpl", { Ew, Gw } }, + { "movs{||lq|xd}", { Gv, Ed } }, + }, +}; + +static const struct dis386 three_byte_table[][256] = { + /* THREE_BYTE_0 */ + { + /* 00 */ + { "pshufb", { MX, EM } }, + { "phaddw", { MX, EM } }, + { "phaddd", { MX, EM } }, + { "phaddsw", { MX, EM } }, + { "pmaddubsw", { MX, EM } }, + { "phsubw", { MX, EM } }, + { "phsubd", { MX, EM } }, + { "phsubsw", { MX, EM } }, + /* 08 */ + { "psignb", { MX, EM } }, + { "psignw", { MX, EM } }, + { "psignd", { MX, EM } }, + { "pmulhrsw", { MX, EM } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 10 */ + { PREGRP39 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP40 }, + { PREGRP41 }, + { "(bad)", { XX } }, + { PREGRP42 }, + /* 18 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pabsb", { MX, EM } }, + { "pabsw", { MX, EM } }, + { "pabsd", { MX, EM } }, + { "(bad)", { XX } }, + /* 20 */ + { PREGRP43 }, + { PREGRP44 }, + { PREGRP45 }, + { PREGRP46 }, + { PREGRP47 }, + { PREGRP48 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 28 */ + { PREGRP49 }, + { PREGRP50 }, + { PREGRP51 }, + { PREGRP52 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 30 */ + { PREGRP53 }, + { PREGRP54 }, + { PREGRP55 }, + { PREGRP56 }, + { PREGRP57 }, + { PREGRP58 }, + { "(bad)", { XX } }, + { PREGRP86 }, + /* 38 */ + { PREGRP59 }, + { PREGRP60 }, + { PREGRP61 }, + { PREGRP62 }, + { PREGRP63 }, + { PREGRP64 }, + { PREGRP65 }, + { PREGRP66 }, + /* 40 */ + { PREGRP67 }, + { PREGRP68 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 48 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 50 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 58 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 60 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 68 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 70 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 78 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 80 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 88 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 90 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 98 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f0 */ + { PREGRP87 }, + { PREGRP88 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* THREE_BYTE_1 */ + { + /* 00 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 08 */ + { PREGRP69 }, + { PREGRP70 }, + { PREGRP71 }, + { PREGRP72 }, + { PREGRP73 }, + { PREGRP74 }, + { PREGRP75 }, + { "palignr", { MX, EM, Ib } }, + /* 10 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP76 }, + { PREGRP77 }, + { PREGRP78 }, + { PREGRP79 }, + /* 18 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 20 */ + { PREGRP80 }, + { PREGRP81 }, + { PREGRP82 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 28 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 30 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 38 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 40 */ + { PREGRP83 }, + { PREGRP84 }, + { PREGRP85 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 48 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 50 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 58 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 60 */ + { PREGRP89 }, + { PREGRP90 }, + { PREGRP91 }, + { PREGRP92 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 68 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 70 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 78 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 80 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 88 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 90 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 98 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + } +}; + +#define INTERNAL_DISASSEMBLER_ERROR _("") + +static void +ckprefix (void) +{ + int newrex; + rex = 0; + prefixes = 0; + used_prefixes = 0; + rex_used = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + newrex = 0; + switch (*codep) + { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (address_mode == mode_64bit) + newrex = *codep; + else + return; + break; + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADDR; + break; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes || rex) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; + break; + default: + return; + } + /* Rex is ignored when followed by another prefix. */ + if (rex) + { + rex_used = rex; + return; + } + rex = newrex; + codep++; + } +} + +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (int pref, int sizeflag) +{ + static const char * const rexes [16] = + { + "rex", /* 0x40 */ + "rex.B", /* 0x41 */ + "rex.X", /* 0x42 */ + "rex.XB", /* 0x43 */ + "rex.R", /* 0x44 */ + "rex.RB", /* 0x45 */ + "rex.RX", /* 0x46 */ + "rex.RXB", /* 0x47 */ + "rex.W", /* 0x48 */ + "rex.WB", /* 0x49 */ + "rex.WX", /* 0x4a */ + "rex.WXB", /* 0x4b */ + "rex.WR", /* 0x4c */ + "rex.WRB", /* 0x4d */ + "rex.WRX", /* 0x4e */ + "rex.WRXB", /* 0x4f */ + }; + + switch (pref) + { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + return rexes [pref - 0x40]; + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + if (address_mode == mode_64bit) + return (sizeflag & AFLAG) ? "addr32" : "addr64"; + else + return (sizeflag & AFLAG) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op_out[MAX_OPERANDS][100]; +static int op_ad, op_index[MAX_OPERANDS]; +static int two_source_ops; +static bfd_vma op_address[MAX_OPERANDS]; +static bfd_vma op_riprel[MAX_OPERANDS]; +static bfd_vma start_pc; + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +int +print_insn_i386 (bfd_vma pc, disassemble_info *info) +{ + intel_syntax = -1; + + return print_insn (pc, info); +} + +static int +print_insn (bfd_vma pc, disassemble_info *info) +{ + const struct dis386 *dp; + int i; + char *op_txt[MAX_OPERANDS]; + int needcomma; + unsigned char uses_DATA_prefix, uses_LOCK_prefix; + unsigned char uses_REPNZ_prefix, uses_REPZ_prefix; + int sizeflag; + const char *p; + struct dis_private priv; + unsigned char op; + + if (info->mach == bfd_mach_x86_64_intel_syntax + || info->mach == bfd_mach_x86_64) + address_mode = mode_64bit; + else + address_mode = mode_32bit; + + if (intel_syntax == (char) -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_x86_64 + || info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax) + priv.orig_sizeflag = AFLAG | DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + priv.orig_sizeflag = 0; + else + abort (); + + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86-64", 6) == 0) + { + address_mode = mode_64bit; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + address_mode = mode_32bit; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + address_mode = mode_16bit; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (address_mode == mode_64bit) + { + if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '6' && p[5] == '4') + priv.orig_sizeflag |= AFLAG; + } + else + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; + + info->private_data = &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + + obuf[0] = 0; + for (i = 0; i < MAX_OPERANDS; ++i) + { + op_out[i][0] = 0; + op_index[i] = -1; + } + + the_info = info; + start_pc = pc; + start_codep = priv.the_buffer; + codep = priv.the_buffer; + + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) + { + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) priv.the_buffer[0]); + } + + return 1; + } + + return -1; + } + + obufp = obuf; + ckprefix (); + + insn_codep = codep; + sizeflag = priv.orig_sizeflag; + + FETCH_DATA (info, codep + 1); + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + + if (((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + || (rex && rex_used)) + { + const char *name; + + /* fwait not followed by floating point instruction, or rex followed + by other prefixes. Print the first prefix. */ + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + op = 0; + if (*codep == 0x0f) + { + unsigned char threebyte; + FETCH_DATA (info, codep + 2); + threebyte = *++codep; + dp = &dis386_twobyte[threebyte]; + need_modrm = twobyte_has_modrm[*codep]; + uses_DATA_prefix = twobyte_uses_DATA_prefix[*codep]; + uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[*codep]; + uses_REPZ_prefix = twobyte_uses_REPZ_prefix[*codep]; + uses_LOCK_prefix = (*codep & ~0x02) == 0x20; + codep++; + if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) + { + FETCH_DATA (info, codep + 2); + op = *codep++; + switch (threebyte) + { + case 0x38: + uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op]; + uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op]; + uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op]; + break; + case 0x3a: + uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op]; + uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op]; + uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op]; + break; + default: + break; + } + } + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + uses_DATA_prefix = 0; + uses_REPNZ_prefix = 0; + /* pause is 0xf3 0x90. */ + uses_REPZ_prefix = *codep == 0x90; + uses_LOCK_prefix = 0; + codep++; + } + + if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ)) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + + if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax) + { + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + } + + if (!uses_DATA_prefix && (prefixes & PREFIX_DATA)) + { + sizeflag ^= DFLAG; + if (dp->op[2].bytemode == cond_jump_mode + && dp->op[0].bytemode == v_mode + && !intel_syntax) + { + if (sizeflag & DFLAG) + oappend ("data32 "); + else + oappend ("data16 "); + used_prefixes |= PREFIX_DATA; + } + } + + if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) + { + dp = &three_byte_table[dp->op[1].bytemode][op]; + modrm.mod = (*codep >> 6) & 3; + modrm.reg = (*codep >> 3) & 7; + modrm.rm = *codep & 7; + } + else if (need_modrm) + { + FETCH_DATA (info, codep + 1); + modrm.mod = (*codep >> 6) & 3; + modrm.reg = (*codep >> 3) & 7; + modrm.rm = *codep & 7; + } + + if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) + { + dofloat (sizeflag); + } + else + { + int index; + if (dp->name == NULL) + { + switch (dp->op[0].bytemode) + { + case USE_GROUPS: + dp = &grps[dp->op[1].bytemode][modrm.reg]; + break; + + case USE_PREFIX_USER_TABLE: + index = 0; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + index = 1; + else + { + /* We should check PREFIX_REPNZ and PREFIX_REPZ + before PREFIX_DATA. */ + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + index = 3; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + index = 2; + } + } + dp = &prefix_user_table[dp->op[1].bytemode][index]; + break; + + case X86_64_SPECIAL: + index = address_mode == mode_64bit ? 1 : 0; + dp = &x86_64_table[dp->op[1].bytemode][index]; + break; + + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + if (putop (dp->name, sizeflag) == 0) + { + for (i = 0; i < MAX_OPERANDS; ++i) + { + obufp = op_out[i]; + op_ad = MAX_OPERANDS - 1 - i; + if (dp->op[i].rtn) + (*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag); + } + } + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + if (rex & ~rex_used) + { + const char *name; + name = prefix_name (rex | 0x40, priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s ", name); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) + { + bfd_vma riprel; + + for (i = 0; i < MAX_OPERANDS; ++i) + op_txt[i] = op_out[i]; + + for (i = 0; i < (MAX_OPERANDS >> 1); ++i) + { + op_ad = op_index[i]; + op_index[i] = op_index[MAX_OPERANDS - 1 - i]; + op_index[MAX_OPERANDS - 1 - i] = op_ad; + riprel = op_riprel[i]; + op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i]; + op_riprel[MAX_OPERANDS - 1 - i] = riprel; + } + } + else + { + for (i = 0; i < MAX_OPERANDS; ++i) + op_txt[MAX_OPERANDS - 1 - i] = op_out[i]; + } + + needcomma = 0; + for (i = 0; i < MAX_OPERANDS; ++i) + if (*op_txt[i]) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[i] != -1 && !op_riprel[i]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info); + else + (*info->fprintf_func) (info->stream, "%s", op_txt[i]); + needcomma = 1; + } + + for (i = 0; i < MAX_OPERANDS; i++) + if (op_index[i] != -1 && op_riprel[i]) + { + (*info->fprintf_func) (info->stream, " # "); + (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + + op_address[op_index[i]]), info); + break; + } + return codep - priv.the_buffer; +} + +static const char *float_mem[] = { + /* d8 */ + "fadd{s||s|}", + "fmul{s||s|}", + "fcom{s||s|}", + "fcomp{s||s|}", + "fsub{s||s|}", + "fsubr{s||s|}", + "fdiv{s||s|}", + "fdivr{s||s|}", + /* d9 */ + "fld{s||s|}", + "(bad)", + "fst{s||s|}", + "fstp{s||s|}", + "fldenvIC", + "fldcw", + "fNstenvIC", + "fNstcw", + /* da */ + "fiadd{l||l|}", + "fimul{l||l|}", + "ficom{l||l|}", + "ficomp{l||l|}", + "fisub{l||l|}", + "fisubr{l||l|}", + "fidiv{l||l|}", + "fidivr{l||l|}", + /* db */ + "fild{l||l|}", + "fisttp{l||l|}", + "fist{l||l|}", + "fistp{l||l|}", + "(bad)", + "fld{t||t|}", + "(bad)", + "fstp{t||t|}", + /* dc */ + "fadd{l||l|}", + "fmul{l||l|}", + "fcom{l||l|}", + "fcomp{l||l|}", + "fsub{l||l|}", + "fsubr{l||l|}", + "fdiv{l||l|}", + "fdivr{l||l|}", + /* dd */ + "fld{l||l|}", + "fisttp{ll||ll|}", + "fst{l||l|}", + "fstp{l||l|}", + "frstorIC", + "(bad)", + "fNsaveIC", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "fisttp", + "fist", + "fistp", + "fbld", + "fild{ll||ll|}", + "fbstp", + "fistp{ll||ll|}", +}; + +static const unsigned char float_mem_mode[] = { + /* d8 */ + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + /* d9 */ + d_mode, + 0, + d_mode, + d_mode, + 0, + w_mode, + 0, + w_mode, + /* da */ + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + /* db */ + d_mode, + d_mode, + d_mode, + d_mode, + 0, + t_mode, + 0, + t_mode, + /* dc */ + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + /* dd */ + q_mode, + q_mode, + q_mode, + q_mode, + 0, + 0, + 0, + w_mode, + /* de */ + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + /* df */ + w_mode, + w_mode, + w_mode, + w_mode, + t_mode, + q_mode, + t_mode, + q_mode +}; + +#define ST { OP_ST, 0 } +#define STi { OP_STi, 0 } + +#define FGRPd9_2 NULL, { { NULL, 0 } } +#define FGRPd9_4 NULL, { { NULL, 1 } } +#define FGRPd9_5 NULL, { { NULL, 2 } } +#define FGRPd9_6 NULL, { { NULL, 3 } } +#define FGRPd9_7 NULL, { { NULL, 4 } } +#define FGRPda_5 NULL, { { NULL, 5 } } +#define FGRPdb_4 NULL, { { NULL, 6 } } +#define FGRPde_3 NULL, { { NULL, 7 } } +#define FGRPdf_4 NULL, { { NULL, 8 } } + +static const struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", { ST, STi } }, + { "fmul", { ST, STi } }, + { "fcom", { STi } }, + { "fcomp", { STi } }, + { "fsub", { ST, STi } }, + { "fsubr", { ST, STi } }, + { "fdiv", { ST, STi } }, + { "fdivr", { ST, STi } }, + }, + /* d9 */ + { + { "fld", { STi } }, + { "fxch", { STi } }, + { FGRPd9_2 }, + { "(bad)", { XX } }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", { ST, STi } }, + { "fcmove", { ST, STi } }, + { "fcmovbe",{ ST, STi } }, + { "fcmovu", { ST, STi } }, + { "(bad)", { XX } }, + { FGRPda_5 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* db */ + { + { "fcmovnb",{ ST, STi } }, + { "fcmovne",{ ST, STi } }, + { "fcmovnbe",{ ST, STi } }, + { "fcmovnu",{ ST, STi } }, + { FGRPdb_4 }, + { "fucomi", { ST, STi } }, + { "fcomi", { ST, STi } }, + { "(bad)", { XX } }, + }, + /* dc */ + { + { "fadd", { STi, ST } }, + { "fmul", { STi, ST } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, +#if SYSV386_COMPAT + { "fsub", { STi, ST } }, + { "fsubr", { STi, ST } }, + { "fdiv", { STi, ST } }, + { "fdivr", { STi, ST } }, +#else + { "fsubr", { STi, ST } }, + { "fsub", { STi, ST } }, + { "fdivr", { STi, ST } }, + { "fdiv", { STi, ST } }, +#endif + }, + /* dd */ + { + { "ffree", { STi } }, + { "(bad)", { XX } }, + { "fst", { STi } }, + { "fstp", { STi } }, + { "fucom", { STi } }, + { "fucomp", { STi } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* de */ + { + { "faddp", { STi, ST } }, + { "fmulp", { STi, ST } }, + { "(bad)", { XX } }, + { FGRPde_3 }, +#if SYSV386_COMPAT + { "fsubp", { STi, ST } }, + { "fsubrp", { STi, ST } }, + { "fdivp", { STi, ST } }, + { "fdivrp", { STi, ST } }, +#else + { "fsubrp", { STi, ST } }, + { "fsubp", { STi, ST } }, + { "fdivrp", { STi, ST } }, + { "fdivp", { STi, ST } }, +#endif + }, + /* df */ + { + { "ffreep", { STi } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { FGRPdf_4 }, + { "fucomip", { ST, STi } }, + { "fcomip", { ST, STi } }, + { "(bad)", { XX } }, + }, +}; + +static const char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (int sizeflag) +{ + const struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (modrm.mod != 3) + { + int fp_indx = (floatop - 0xd8) * 8 + modrm.reg; + + putop (float_mem[fp_indx], sizeflag); + obufp = op_out[0]; + op_ad = 2; + OP_E (float_mem_mode[fp_indx], sizeflag); + return; + } + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + dp = &float_reg[floatop - 0xd8][modrm.reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag); + + /* Instruction fnstsw is only one with strange arg. */ + if (floatop == 0xdf && codep[-1] == 0xe0) + pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]); + } + else + { + putop (dp->name, sizeflag); + + obufp = op_out[0]; + op_ad = 2; + if (dp->op[0].rtn) + (*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag); + + obufp = op_out[1]; + op_ad = 1; + if (dp->op[1].rtn) + (*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag); + } +} + +static void +OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + oappend ("%st" + intel_syntax); +} + +static void +OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +/* Capital letters in template are macros. */ +static int +putop (const char *template, int sizeflag) +{ + const char *p; + int alt = 0; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case '{': + alt = 0; + if (intel_syntax) + alt += 1; + if (address_mode == mode_64bit) + alt += 2; + while (alt != 0) + { + while (*++p != '|') + { + if (*p == '}') + { + /* Alternative not valid. */ + pstrcpy (obuf, sizeof(obuf), "(bad)"); + obufp = obuf + 5; + return 1; + } + else if (*p == '\0') + abort (); + } + alt--; + } + /* Fall through. */ + case 'I': + alt = 1; + continue; + case '|': + while (*++p != '}') + { + if (*p == '\0') + abort (); + } + break; + case '}': + break; + case 'A': + if (intel_syntax) + break; + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; + break; + case 'C': + if (intel_syntax && !alt) + break; + if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = intel_syntax ? 'w' : 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'D': + if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS)) + break; + USED_REX (REX_W); + if (modrm.mod == 3) + { + if (rex & REX_W) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + else + *obufp++ = 'w'; + break; + case 'E': /* For jcxz/jecxz */ + if (address_mode == mode_64bit) + { + if (sizeflag & AFLAG) + *obufp++ = 'r'; + else + *obufp++ = 'e'; + } + else + if (sizeflag & AFLAG) + *obufp++ = 'e'; + used_prefixes |= (prefixes & PREFIX_ADDR); + break; + case 'F': + if (intel_syntax) + break; + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & AFLAG) + *obufp++ = address_mode == mode_64bit ? 'q' : 'l'; + else + *obufp++ = address_mode == mode_64bit ? 'l' : 'w'; + used_prefixes |= (prefixes & PREFIX_ADDR); + } + break; + case 'G': + if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS))) + break; + if ((rex & REX_W) || (sizeflag & DFLAG)) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'H': + if (intel_syntax) + break; + if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS + || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) + { + used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); + *obufp++ = ','; + *obufp++ = 'p'; + if (prefixes & PREFIX_DS) + *obufp++ = 't'; + else + *obufp++ = 'n'; + } + break; + case 'J': + if (intel_syntax) + break; + *obufp++ = 'l'; + break; + case 'K': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else + *obufp++ = 'd'; + break; + case 'Z': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS)) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'L': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'O': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'o'; + else if (intel_syntax && (sizeflag & DFLAG)) + *obufp++ = 'q'; + else + *obufp++ = 'd'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'T': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) + || (rex & REX_W) + || (sizeflag & SUFFIX_ALWAYS)) + { + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'U': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'Q': + if (intel_syntax && !alt) + break; + USED_REX (REX_W); + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + { + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'R': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + { + if (intel_syntax) + *obufp++ = 'd'; + else + *obufp++ = 'l'; + } + else + *obufp++ = 'w'; + if (intel_syntax && !p[1] + && ((rex & REX_W) || (sizeflag & DFLAG))) + *obufp++ = 'e'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'V': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'S': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + { + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'X': + if (prefixes & PREFIX_DATA) + *obufp++ = 'd'; + else + *obufp++ = 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'Y': + if (intel_syntax) + break; + if (rex & REX_W) + { + USED_REX (REX_W); + *obufp++ = 'q'; + } + break; + /* implicit operand size 'l' for i386 or 'q' for x86-64 */ + case 'W': + /* operand size flag for cwtl, cbtw */ + USED_REX (REX_W); + if (rex & REX_W) + { + if (intel_syntax) + *obufp++ = 'd'; + else + *obufp++ = 'l'; + } + else if (sizeflag & DFLAG) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + alt = 0; + } + *obufp = 0; + return 0; +} + +static void +oappend (const char *s) +{ + strcpy (obufp, s); + obufp += strlen (s); +} + +static void +append_seg (void) +{ + if (prefixes & PREFIX_CS) + { + used_prefixes |= PREFIX_CS; + oappend ("%cs:" + intel_syntax); + } + if (prefixes & PREFIX_DS) + { + used_prefixes |= PREFIX_DS; + oappend ("%ds:" + intel_syntax); + } + if (prefixes & PREFIX_SS) + { + used_prefixes |= PREFIX_SS; + oappend ("%ss:" + intel_syntax); + } + if (prefixes & PREFIX_ES) + { + used_prefixes |= PREFIX_ES; + oappend ("%es:" + intel_syntax); + } + if (prefixes & PREFIX_FS) + { + used_prefixes |= PREFIX_FS; + oappend ("%fs:" + intel_syntax); + } + if (prefixes & PREFIX_GS) + { + used_prefixes |= PREFIX_GS; + oappend ("%gs:" + intel_syntax); + } +} + +static void +OP_indirE (int bytemode, int sizeflag) +{ + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); +} + +static void +print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) +{ + if (address_mode == mode_64bit) + { + if (hex) + { + char tmp[30]; + int i; + buf[0] = '0'; + buf[1] = 'x'; + snprintf_vma (tmp, sizeof(tmp), disp); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + pstrcpy (buf + 2, bufsize - 2, tmp + i); + } + else + { + bfd_signed_vma v = disp; + char tmp[30]; + int i; + if (v < 0) + { + *(buf++) = '-'; + v = -disp; + /* Check for possible overflow on 0x8000000000000000. */ + if (v < 0) + { + pstrcpy (buf, bufsize, "9223372036854775808"); + return; + } + } + if (!v) + { + pstrcpy (buf, bufsize, "0"); + return; + } + + i = 0; + tmp[29] = 0; + while (v) + { + tmp[28 - i] = (v % 10) + '0'; + v /= 10; + i++; + } + pstrcpy (buf, bufsize, tmp + 29 - i); + } + } + else + { + if (hex) + snprintf (buf, bufsize, "0x%x", (unsigned int) disp); + else + snprintf (buf, bufsize, "%d", (int) disp); + } +} + +/* Put DISP in BUF as signed hex number. */ + +static void +print_displacement (char *buf, bfd_vma disp) +{ + bfd_signed_vma val = disp; + char tmp[30]; + int i, j = 0; + + if (val < 0) + { + buf[j++] = '-'; + val = -disp; + + /* Check for possible overflow. */ + if (val < 0) + { + switch (address_mode) + { + case mode_64bit: + strcpy (buf + j, "0x8000000000000000"); + break; + case mode_32bit: + strcpy (buf + j, "0x80000000"); + break; + case mode_16bit: + strcpy (buf + j, "0x8000"); + break; + } + return; + } + } + + buf[j++] = '0'; + buf[j++] = 'x'; + + snprintf_vma (tmp, sizeof(tmp), val); + for (i = 0; tmp[i] == '0'; i++) + continue; + if (tmp[i] == '\0') + i--; + strcpy (buf + j, tmp + i); +} + +static void +intel_operand_size (int bytemode, int sizeflag) +{ + switch (bytemode) + { + case b_mode: + case dqb_mode: + oappend ("BYTE PTR "); + break; + case w_mode: + case dqw_mode: + oappend ("WORD PTR "); + break; + case stack_v_mode: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + oappend ("QWORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + /* FALLTHRU */ + case v_mode: + case dq_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend ("QWORD PTR "); + else if ((sizeflag & DFLAG) || bytemode == dq_mode) + oappend ("DWORD PTR "); + else + oappend ("WORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case z_mode: + if ((rex & REX_W) || (sizeflag & DFLAG)) + *obufp++ = 'D'; + oappend ("WORD PTR "); + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case d_mode: + case dqd_mode: + oappend ("DWORD PTR "); + break; + case q_mode: + oappend ("QWORD PTR "); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend ("QWORD PTR "); + else + oappend ("DWORD PTR "); + break; + case f_mode: + if (sizeflag & DFLAG) + oappend ("FWORD PTR "); + else + oappend ("DWORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case t_mode: + oappend ("TBYTE PTR "); + break; + case x_mode: + oappend ("XMMWORD PTR "); + break; + case o_mode: + oappend ("OWORD PTR "); + break; + default: + break; + } +} + +static void +OP_E (int bytemode, int sizeflag) +{ + bfd_vma disp; + int add = 0; + int riprel = 0; + USED_REX (REX_B); + if (rex & REX_B) + add += 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + if (modrm.mod == 3) + { + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[modrm.rm + add]); + else + oappend (names8[modrm.rm + add]); + break; + case w_mode: + oappend (names16[modrm.rm + add]); + break; + case d_mode: + oappend (names32[modrm.rm + add]); + break; + case q_mode: + oappend (names64[modrm.rm + add]); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend (names64[modrm.rm + add]); + else + oappend (names32[modrm.rm + add]); + break; + case stack_v_mode: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + oappend (names64[modrm.rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + bytemode = v_mode; + /* FALLTHRU */ + case v_mode: + case dq_mode: + case dqb_mode: + case dqd_mode: + case dqw_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.rm + add]); + else if ((sizeflag & DFLAG) || bytemode != v_mode) + oappend (names32[modrm.rm + add]); + else + oappend (names16[modrm.rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + return; + } + + disp = 0; + if (intel_syntax) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + { + /* 32/64 bit address mode */ + int havedisp; + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = modrm.rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + index = (*codep >> 3) & 7; + if (address_mode == mode_64bit || index != 0x4) + /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ + scale = (*codep >> 6) & 3; + base = *codep & 7; + USED_REX (REX_X); + if (rex & REX_X) + index += 8; + codep++; + } + base += add; + + switch (modrm.mod) + { + case 0: + if ((base & 7) == 5) + { + havebase = 0; + if (address_mode == mode_64bit && !havesib) + riprel = 1; + disp = get32s (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32s (); + break; + } + + havedisp = havebase || (havesib && (index != 4 || scale != 0)); + + if (!intel_syntax) + if (modrm.mod != 0 || (base & 7) == 5) + { + if (havedisp || riprel) + print_displacement (scratchbuf, disp); + else + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); + if (riprel) + { + set_op (disp, 1); + oappend ("(%rip)"); + } + } + + if (havedisp || (intel_syntax && riprel)) + { + *obufp++ = open_char; + if (intel_syntax && riprel) + { + set_op (disp, 1); + oappend ("rip"); + } + *obufp = '\0'; + if (havebase) + oappend (address_mode == mode_64bit && (sizeflag & AFLAG) + ? names64[base] : names32[base]); + if (havesib) + { + if (index != 4) + { + if (!intel_syntax || havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + oappend (address_mode == mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + } + if (scale != 0 || (!intel_syntax && index != 4)) + { + *obufp++ = scale_char; + *obufp = '\0'; + snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale); + oappend (scratchbuf); + } + } + if (intel_syntax + && (disp || modrm.mod != 0 || (base & 7) == 5)) + { + if ((bfd_signed_vma) disp >= 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + else if (modrm.mod != 1) + { + *obufp++ = '-'; + *obufp = '\0'; + disp = - (bfd_signed_vma) disp; + } + + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (modrm.mod != 0 || (base & 7) == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); + } + } + } + else + { /* 16 bit address mode */ + switch (modrm.mod) + { + case 0: + if (modrm.rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (!intel_syntax) + if (modrm.mod != 0 || modrm.rm == 6) + { + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + if (modrm.mod != 0 || modrm.rm != 6) + { + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[modrm.rm]); + if (intel_syntax + && (disp || modrm.mod != 0 || modrm.rm == 6)) + { + if ((bfd_signed_vma) disp >= 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + else if (modrm.mod != 1) + { + *obufp++ = '-'; + *obufp = '\0'; + disp = - (bfd_signed_vma) disp; + } + + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, + disp & 0xffff); + oappend (scratchbuf); + } + } +} + +static void +OP_G (int bytemode, int sizeflag) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add += 8; + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[modrm.reg + add]); + else + oappend (names8[modrm.reg + add]); + break; + case w_mode: + oappend (names16[modrm.reg + add]); + break; + case d_mode: + oappend (names32[modrm.reg + add]); + break; + case q_mode: + oappend (names64[modrm.reg + add]); + break; + case v_mode: + case dq_mode: + case dqb_mode: + case dqd_mode: + case dqw_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.reg + add]); + else if ((sizeflag & DFLAG) || bytemode != v_mode) + oappend (names32[modrm.reg + add]); + else + oappend (names16[modrm.reg + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend (names64[modrm.reg + add]); + else + oappend (names32[modrm.reg + add]); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } +} + +static bfd_vma +get64 (void) +{ + bfd_vma x; +#ifdef BFD64 + unsigned int a; + unsigned int b; + + FETCH_DATA (the_info, codep + 8); + a = *codep++ & 0xff; + a |= (*codep++ & 0xff) << 8; + a |= (*codep++ & 0xff) << 16; + a |= (*codep++ & 0xff) << 24; + b = *codep++ & 0xff; + b |= (*codep++ & 0xff) << 8; + b |= (*codep++ & 0xff) << 16; + b |= (*codep++ & 0xff) << 24; + x = a + ((bfd_vma) b << 32); +#else + abort (); + x = 0; +#endif + return x; +} + +static bfd_signed_vma +get32 (void) +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + return x; +} + +static bfd_signed_vma +get32s (void) +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + + x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); + + return x; +} + +static int +get16 (void) +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return x; +} + +static void +set_op (bfd_vma op, int riprel) +{ + op_index[op_ad] = op_ad; + if (address_mode == mode_64bit) + { + op_address[op_ad] = op; + op_riprel[op_ad] = riprel; + } + else + { + /* Mask to get a 32-bit address. */ + op_address[op_ad] = op & 0xffffffff; + op_riprel[op_ad] = riprel & 0xffffffff; + } +} + +static void +OP_REG (int code, int sizeflag) +{ + const char *s; + int add = 0; + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + + switch (code) + { + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg + add]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg + add]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg + add]; + else + s = names8[code - al_reg]; + break; + case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: + case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + s = names64[code - rAX_reg + add]; + break; + } + code += eAX_reg - rAX_reg; + /* Fall through. */ + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_W); + if (rex & REX_W) + s = names64[code - eAX_reg + add]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg + add]; + else + s = names16[code - eAX_reg + add]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_IMREG (int code, int sizeflag) +{ + const char *s; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "dx"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg]; + else + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_W); + if (rex & REX_W) + s = names64[code - eAX_reg]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case z_mode_ax_reg: + if ((rex & REX_W) || (sizeflag & DFLAG)) + s = *names32; + else + s = *names16; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case q_mode: + if (address_mode == mode_64bit) + { + op = get32s (); + break; + } + /* Fall through. */ + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + case const_1_mode: + if (intel_syntax) + oappend ("1"); + return; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_I64 (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + if (address_mode != mode_64bit) + { + OP_I (bytemode, sizeflag); + return; + } + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get64 (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + mask = 0xffffffff; + break; + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32s (); + mask = 0xffffffff; + } + else + { + mask = 0xffffffff; + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + mask = 0xffffffff; + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_J (int bytemode, int sizeflag) +{ + bfd_vma disp; + bfd_vma mask = -1; + bfd_vma segment = 0; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if ((sizeflag & DFLAG) || (rex & REX_W)) + disp = get32s (); + else + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + /* In 16bit mode, address is wrapped around at 64k within + the same segment. Otherwise, a data16 prefix on a jump + instruction means that the pc is masked to 16 bits after + the displacement is added! */ + mask = 0xffff; + if ((prefixes & PREFIX_DATA) == 0) + segment = ((start_pc + codep - start_codep) + & ~((bfd_vma) 0xffff)); + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + disp = ((start_pc + codep - start_codep + disp) & mask) | segment; + set_op (disp, 0); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); +} + +static void +OP_SEG (int bytemode, int sizeflag) +{ + if (bytemode == w_mode) + oappend (names_seg[modrm.reg]); + else + OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag); +} + +static void +OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) +{ + int seg, offset; + + if (sizeflag & DFLAG) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + if (intel_syntax) + snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset); + else + snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); +} + +static void +OP_OFF (int bytemode, int sizeflag) +{ + bfd_vma off; + + if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + off = get32 (); + else + off = get16 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); + oappend (scratchbuf); +} + +static void +OP_OFF64 (int bytemode, int sizeflag) +{ + bfd_vma off; + + if (address_mode != mode_64bit + || (prefixes & PREFIX_ADDR)) + { + OP_OFF (bytemode, sizeflag); + return; + } + + if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + off = get64 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); + oappend (scratchbuf); +} + +static void +ptr_reg (int code, int sizeflag) +{ + const char *s; + + *obufp++ = open_char; + used_prefixes |= (prefixes & PREFIX_ADDR); + if (address_mode == mode_64bit) + { + if (!(sizeflag & AFLAG)) + s = names32[code - eAX_reg]; + else + s = names64[code - eAX_reg]; + } + else if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + *obufp++ = close_char; + *obufp = 0; +} + +static void +OP_ESreg (int code, int sizeflag) +{ + if (intel_syntax) + { + switch (codep[-1]) + { + case 0x6d: /* insw/insl */ + intel_operand_size (z_mode, sizeflag); + break; + case 0xa5: /* movsw/movsl/movsq */ + case 0xa7: /* cmpsw/cmpsl/cmpsq */ + case 0xab: /* stosw/stosl */ + case 0xaf: /* scasw/scasl */ + intel_operand_size (v_mode, sizeflag); + break; + default: + intel_operand_size (b_mode, sizeflag); + } + } + oappend ("%es:" + intel_syntax); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (int code, int sizeflag) +{ + if (intel_syntax) + { + switch (codep[-1]) + { + case 0x6f: /* outsw/outsl */ + intel_operand_size (z_mode, sizeflag); + break; + case 0xa5: /* movsw/movsl/movsq */ + case 0xa7: /* cmpsw/cmpsl/cmpsq */ + case 0xad: /* lodsw/lodsl/lodsq */ + intel_operand_size (v_mode, sizeflag); + break; + default: + intel_operand_size (b_mode, sizeflag); + } + } + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_seg (); + ptr_reg (code, sizeflag); +} + +static void +OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + if (rex & REX_R) + { + USED_REX (REX_R); + add = 8; + } + else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK)) + { + used_prefixes |= PREFIX_LOCK; + add = 8; + } + snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + if (intel_syntax) + snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add); + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add); + oappend (scratchbuf); +} + +static void +OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_R (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + { + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); + } + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EM (int bytemode, int sizeflag) +{ + if (modrm.mod != 3) + { + if (intel_syntax && bytemode == v_mode) + { + bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; + used_prefixes |= (prefixes & PREFIX_DATA); + } + OP_E (bytemode, sizeflag); + return; + } + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + { + int add = 0; + + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); + } + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +/* cvt* are the only instructions in sse2 which have + both SSE and MMX operands and also have 0x66 prefix + in their opcode. 0x66 was originally used to differentiate + between SSE and MMX instruction(operands). So we have to handle the + cvt* separately using OP_EMC and OP_MXC */ +static void +OP_EMC (int bytemode, int sizeflag) +{ + if (modrm.mod != 3) + { + if (intel_syntax && bytemode == v_mode) + { + bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; + used_prefixes |= (prefixes & PREFIX_DATA); + } + OP_E (bytemode, sizeflag); + return; + } + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + used_prefixes |= (prefixes & PREFIX_DATA); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + used_prefixes |= (prefixes & PREFIX_DATA); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EX (int bytemode, int sizeflag) +{ + int add = 0; + if (modrm.mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MS (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_XS (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_EX (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_M (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */ + BadOp (); + else + OP_E (bytemode, sizeflag); +} + +static void +OP_0f07 (int bytemode, int sizeflag) +{ + if (modrm.mod != 3 || modrm.rm != 0) + BadOp (); + else + OP_E (bytemode, sizeflag); +} + +static void +OP_0fae (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + { + if (modrm.reg == 7) + strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); + + if (modrm.reg < 5 || modrm.rm != 0) + { + BadOp (); /* bad sfence, mfence, or lfence */ + return; + } + } + else if (modrm.reg != 7) + { + BadOp (); /* bad clflush */ + return; + } + + OP_E (bytemode, sizeflag); +} + +/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in + 32bit mode and "xchg %rax,%rax" in 64bit mode. */ + +static void +NOP_Fixup1 (int bytemode, int sizeflag) +{ + if ((prefixes & PREFIX_DATA) != 0 + || (rex != 0 + && rex != 0x48 + && address_mode == mode_64bit)) + OP_REG (bytemode, sizeflag); + else + strcpy (obuf, "nop"); +} + +static void +NOP_Fixup2 (int bytemode, int sizeflag) +{ + if ((prefixes & PREFIX_DATA) != 0 + || (rex != 0 + && rex != 0x48 + && address_mode == mode_64bit)) + OP_IMREG (bytemode, sizeflag); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen (obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op_out[0][0] = '\0'; + op_out[1][0] = '\0'; + BadOp (); + } +} + +static const char *simd_cmp_op[] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen (obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + char suffix1 = 'p', suffix2 = 's'; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + suffix1 = 's'; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + suffix2 = 'd'; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + suffix1 = 's', suffix2 = 'd'; + } + } + snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op_out[0][0] = '\0'; + op_out[1][0] = '\0'; + BadOp (); + } +} + +static void +SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (modrm.mod == 3) + { + char *p = obuf + strlen (obuf); + *(p + 1) = '\0'; + *p = *(p - 1); + *(p - 1) = *(p - 2); + *(p - 2) = *(p - 3); + *(p - 3) = extrachar; + } +} + +static void +PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) +{ + if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1) + { + /* Override "sidt". */ + size_t olen = strlen (obuf); + char *p = obuf + olen - 4; + const char * const *names = (address_mode == mode_64bit + ? names64 : names32); + + /* We might have a suffix when disassembling with -Msuffix. */ + if (*p == 'i') + --p; + + /* Remove "addr16/addr32" if we aren't in Intel mode. */ + if (!intel_syntax + && (prefixes & PREFIX_ADDR) + && olen >= (4 + 7) + && *(p - 1) == ' ' + && strncmp (p - 7, "addr", 4) == 0 + && (strncmp (p - 3, "16", 2) == 0 + || strncmp (p - 3, "32", 2) == 0)) + p -= 7; + + if (modrm.rm) + { + /* mwait %eax,%ecx */ + strcpy (p, "mwait"); + if (!intel_syntax) + strcpy (op_out[0], names[0]); + } + else + { + /* monitor %eax,%ecx,%edx" */ + strcpy (p, "monitor"); + if (!intel_syntax) + { + const char * const *op1_names; + if (!(prefixes & PREFIX_ADDR)) + op1_names = (address_mode == mode_16bit + ? names16 : names); + else + { + op1_names = (address_mode != mode_32bit + ? names32 : names16); + used_prefixes |= PREFIX_ADDR; + } + strcpy (op_out[0], op1_names[0]); + strcpy (op_out[2], names[2]); + } + } + if (!intel_syntax) + { + strcpy (op_out[1], names[1]); + two_source_ops = 1; + } + + codep++; + } + else + OP_M (0, sizeflag); +} + +static void +SVME_Fixup (int bytemode, int sizeflag) +{ + const char *alt; + char *p; + + switch (*codep) + { + case 0xd8: + alt = "vmrun"; + break; + case 0xd9: + alt = "vmmcall"; + break; + case 0xda: + alt = "vmload"; + break; + case 0xdb: + alt = "vmsave"; + break; + case 0xdc: + alt = "stgi"; + break; + case 0xdd: + alt = "clgi"; + break; + case 0xde: + alt = "skinit"; + break; + case 0xdf: + alt = "invlpga"; + break; + default: + OP_M (bytemode, sizeflag); + return; + } + /* Override "lidt". */ + p = obuf + strlen (obuf) - 4; + /* We might have a suffix. */ + if (*p == 'i') + --p; + strcpy (p, alt); + if (!(prefixes & PREFIX_ADDR)) + { + ++codep; + return; + } + used_prefixes |= PREFIX_ADDR; + switch (*codep++) + { + case 0xdf: + strcpy (op_out[1], names32[1]); + two_source_ops = 1; + /* Fall through. */ + case 0xd8: + case 0xda: + case 0xdb: + *obufp++ = open_char; + if (address_mode == mode_64bit || (sizeflag & AFLAG)) + alt = names32[0]; + else + alt = names16[0]; + strcpy (obufp, alt); + obufp += strlen (alt); + *obufp++ = close_char; + *obufp = '\0'; + break; + } +} + +static void +INVLPG_Fixup (int bytemode, int sizeflag) +{ + const char *alt; + + switch (*codep) + { + case 0xf8: + alt = "swapgs"; + break; + case 0xf9: + alt = "rdtscp"; + break; + default: + OP_M (bytemode, sizeflag); + return; + } + /* Override "invlpg". */ + strcpy (obuf + strlen (obuf) - 6, alt); + codep++; +} + +static void +BadOp (void) +{ + /* Throw away prefixes and 1st. opcode byte. */ + codep = insn_codep + 1; + oappend ("(bad)"); +} + +static void +VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) +{ + if (modrm.mod == 3 + && modrm.reg == 0 + && modrm.rm >=1 + && modrm.rm <= 4) + { + /* Override "sgdt". */ + char *p = obuf + strlen (obuf) - 4; + + /* We might have a suffix when disassembling with -Msuffix. */ + if (*p == 'g') + --p; + + switch (modrm.rm) + { + case 1: + strcpy (p, "vmcall"); + break; + case 2: + strcpy (p, "vmlaunch"); + break; + case 3: + strcpy (p, "vmresume"); + break; + case 4: + strcpy (p, "vmxoff"); + break; + } + + codep++; + } + else + OP_E (0, sizeflag); +} + +static void +OP_VMX (int bytemode, int sizeflag) +{ + used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); + if (prefixes & PREFIX_DATA) + strcpy (obuf, "vmclear"); + else if (prefixes & PREFIX_REPZ) + strcpy (obuf, "vmxon"); + else + strcpy (obuf, "vmptrld"); + OP_E (bytemode, sizeflag); +} + +static void +REP_Fixup (int bytemode, int sizeflag) +{ + /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs, + lods and stos. */ + size_t ilen = 0; + + if (prefixes & PREFIX_REPZ) + switch (*insn_codep) + { + case 0x6e: /* outsb */ + case 0x6f: /* outsw/outsl */ + case 0xa4: /* movsb */ + case 0xa5: /* movsw/movsl/movsq */ + if (!intel_syntax) + ilen = 5; + else + ilen = 4; + break; + case 0xaa: /* stosb */ + case 0xab: /* stosw/stosl/stosq */ + case 0xac: /* lodsb */ + case 0xad: /* lodsw/lodsl/lodsq */ + if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + ilen = 5; + else + ilen = 4; + break; + case 0x6c: /* insb */ + case 0x6d: /* insl/insw */ + if (!intel_syntax) + ilen = 4; + else + ilen = 3; + break; + default: + abort (); + break; + } + + if (ilen != 0) + { + size_t olen; + char *p; + + olen = strlen (obuf); + p = obuf + olen - ilen - 1 - 4; + /* Handle "repz [addr16|addr32]". */ + if ((prefixes & PREFIX_ADDR)) + p -= 1 + 6; + + memmove (p + 3, p + 4, olen - (p + 3 - obuf)); + } + + switch (bytemode) + { + case al_reg: + case eAX_reg: + case indir_dx_reg: + OP_IMREG (bytemode, sizeflag); + break; + case eDI_reg: + OP_ESreg (bytemode, sizeflag); + break; + case eSI_reg: + OP_DSreg (bytemode, sizeflag); + break; + default: + abort (); + break; + } +} + +static void +CMPXCHG8B_Fixup (int bytemode, int sizeflag) +{ + USED_REX (REX_W); + if (rex & REX_W) + { + /* Change cmpxchg8b to cmpxchg16b. */ + char *p = obuf + strlen (obuf) - 2; + strcpy (p, "16b"); + bytemode = o_mode; + } + OP_M (bytemode, sizeflag); +} + +static void +XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg); + oappend (scratchbuf + intel_syntax); +} + +static void +CRC32_Fixup (int bytemode, int sizeflag) +{ + /* Add proper suffix to "crc32". */ + char *p = obuf + strlen (obuf); + + switch (bytemode) + { + case b_mode: + if (intel_syntax) + break; + + *p++ = 'b'; + break; + case v_mode: + if (intel_syntax) + break; + + USED_REX (REX_W); + if (rex & REX_W) + *p++ = 'q'; + else if (sizeflag & DFLAG) + *p++ = 'l'; + else + *p++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + *p = '\0'; + + if (modrm.mod == 3) + { + int add; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + USED_REX (REX_B); + add = (rex & REX_B) ? 8 : 0; + if (bytemode == b_mode) + { + USED_REX (0); + if (rex) + oappend (names8rex[modrm.rm + add]); + else + oappend (names8[modrm.rm + add]); + } + else + { + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.rm + add]); + else if ((prefixes & PREFIX_DATA)) + oappend (names16[modrm.rm + add]); + else + oappend (names32[modrm.rm + add]); + } + } + else + OP_E (bytemode, sizeflag); +} diff --git a/qemu/qemu-git/.svn/text-base/i386.ld.svn-base b/qemu/qemu-git/.svn/text-base/i386.ld.svn-base new file mode 100644 index 0000000..f2dafec --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/i386.ld.svn-base @@ -0,0 +1,141 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/.svn/text-base/ia64.ld.svn-base b/qemu/qemu-git/.svn/text-base/ia64.ld.svn-base new file mode 100644 index 0000000..0c37796 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/ia64.ld.svn-base @@ -0,0 +1,209 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little", + "elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) } + .init : + { + KEEP (*(.init)) + } =0x00300000010070000002000001000400 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x00300000010070000002000001000400 + .fini : + { + KEEP (*(.fini)) + } =0x00300000010070000002000001000400 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .opd : { *(.opd) } + .IA_64.unwind_info : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) } + .IA_64.unwind : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + /* Ensure __gp is outside the range of any normal data. We need to + do this to avoid the linker optimizing the code in op.o and getting + it out of sync with the relocs that we read when processing that + file. A better solution might be to ensure that the dynamically + generated code and static qemu code share a single gp-value. */ + __gp = . + 0x200000; + .got : { *(.got.plt) *(.got) } + .IA_64.pltoff : { *(.IA_64.pltoff) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + . += 0x400000; /* ensure .bss stuff is out of reach of gp */ + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/.svn/text-base/ioport.h.svn-base b/qemu/qemu-git/.svn/text-base/ioport.h.svn-base new file mode 100644 index 0000000..3d3c8a3 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/ioport.h.svn-base @@ -0,0 +1,53 @@ +/* + * defines ioport related functions + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/************************************************************************** + * IO ports API + */ + +#ifndef IOPORT_H +#define IOPORT_H + +#include "qemu-common.h" + +typedef uint32_t pio_addr_t; +#define FMT_pioaddr PRIx32 + +#define MAX_IOPORTS (64 * 1024) +#define IOPORTS_MASK (MAX_IOPORTS - 1) + +/* These should really be in isa.h, but are here to make pc.h happy. */ +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); + +int register_ioport_read(pio_addr_t start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(pio_addr_t start, int length, int size, + IOPortWriteFunc *func, void *opaque); +void isa_unassign_ioport(pio_addr_t start, int length); + + +void cpu_outb(pio_addr_t addr, uint8_t val); +void cpu_outw(pio_addr_t addr, uint16_t val); +void cpu_outl(pio_addr_t addr, uint32_t val); +uint8_t cpu_inb(pio_addr_t addr); +uint16_t cpu_inw(pio_addr_t addr); +uint32_t cpu_inl(pio_addr_t addr); + +#endif /* IOPORT_H */ diff --git a/qemu/qemu-git/.svn/text-base/kvm.h.svn-base b/qemu/qemu-git/.svn/text-base/kvm.h.svn-base new file mode 100644 index 0000000..1c93ac5 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/kvm.h.svn-base @@ -0,0 +1,142 @@ +/* + * QEMU KVM support + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_H +#define QEMU_KVM_H + +#include "config.h" +#include "qemu-queue.h" + +#ifdef CONFIG_KVM +extern int kvm_allowed; + +#define kvm_enabled() (kvm_allowed) +#else +#define kvm_enabled() (0) +#endif + +struct kvm_run; + +/* external API */ + +int kvm_init(int smp_cpus); + +int kvm_init_vcpu(CPUState *env); + +int kvm_cpu_exec(CPUState *env); + +void kvm_set_phys_mem(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset); + +int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + +int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); +int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); +int kvm_set_migration_log(int enable); + +int kvm_has_sync_mmu(void); +int kvm_has_vcpu_events(void); + +void kvm_setup_guest_memory(void *start, size_t size); + +int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); +int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); + +int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, + target_ulong len, int type); +int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, + target_ulong len, int type); +void kvm_remove_all_breakpoints(CPUState *current_env); +int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); + +int kvm_pit_in_kernel(void); +int kvm_irqchip_in_kernel(void); + +/* internal API */ + +struct KVMState; +typedef struct KVMState KVMState; + +int kvm_ioctl(KVMState *s, int type, ...); + +int kvm_vm_ioctl(KVMState *s, int type, ...); + +int kvm_vcpu_ioctl(CPUState *env, int type, ...); + +/* Arch specific hooks */ + +int kvm_arch_post_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run); + +int kvm_arch_pre_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_get_registers(CPUState *env); + +int kvm_arch_put_registers(CPUState *env); + +int kvm_arch_init(KVMState *s, int smp_cpus); + +int kvm_arch_init_vcpu(CPUState *env); + +void kvm_arch_reset_vcpu(CPUState *env); + +struct kvm_guest_debug; +struct kvm_debug_exit_arch; + +struct kvm_sw_breakpoint { + target_ulong pc; + target_ulong saved_insn; + int use_count; + QTAILQ_ENTRY(kvm_sw_breakpoint) entry; +}; + +QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); + +int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info); + +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, + target_ulong pc); + +int kvm_sw_breakpoints_active(CPUState *env); + +int kvm_arch_insert_sw_breakpoint(CPUState *current_env, + struct kvm_sw_breakpoint *bp); +int kvm_arch_remove_sw_breakpoint(CPUState *current_env, + struct kvm_sw_breakpoint *bp); +int kvm_arch_insert_hw_breakpoint(target_ulong addr, + target_ulong len, int type); +int kvm_arch_remove_hw_breakpoint(target_ulong addr, + target_ulong len, int type); +void kvm_arch_remove_all_hw_breakpoints(void); + +void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); + +int kvm_check_extension(KVMState *s, unsigned int extension); + +uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, + int reg); +void kvm_cpu_synchronize_state(CPUState *env); + +/* generic hooks - to be moved/refactored once there are more users */ + +static inline void cpu_synchronize_state(CPUState *env) +{ + if (kvm_enabled()) { + kvm_cpu_synchronize_state(env); + } +} + +#endif diff --git a/qemu/qemu-git/.svn/text-base/m68k-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/m68k-dis.c.svn-base new file mode 100644 index 0000000..d38d5a2 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/m68k-dis.c.svn-base @@ -0,0 +1,5045 @@ +/* This file is composed of several different files from the upstream + sourceware.org CVS. Original file boundaries marked with **** */ + +#include +#include +#include + +#include "dis-asm.h" + +/* **** floatformat.h from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +/*#include "ansidecl.h" */ + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +/* What is the order of the bytes. */ + +enum floatformat_byteorders { + + /* Standard little endian byte order. + EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */ + + floatformat_little, + + /* Standard big endian byte order. + EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */ + + floatformat_big, + + /* Little endian byte order but big endian word order. + EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */ + + floatformat_littlebyte_bigword + +}; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Bias added to a "true" exponent to form the biased exponent. It + is intentionally signed as, otherwize, -exp_bias can turn into a + very large number (e.g., given the exp_bias of 0x3fff and a 64 + bit long, the equation (long)(1 - exp_bias) evaluates to + 4294950914) instead of -16382). */ + int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; + + /* Internal name for debugging. */ + const char *name; + + /* Validator method. */ + int (*is_valid) (const struct floatformat *fmt, const char *from); +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformat for ARM IEEE double, little endian bytes and big endian words */ + +extern const struct floatformat floatformat_ieee_double_littlebyte_bigword; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_m88110_harris_ext; +extern const struct floatformat floatformat_arm_ext_big; +extern const struct floatformat floatformat_arm_ext_littlebyte_bigword; +/* IA-64 Floating Point register spilt into memory. */ +extern const struct floatformat floatformat_ia64_spill_big; +extern const struct floatformat floatformat_ia64_spill_little; +extern const struct floatformat floatformat_ia64_quad_big; +extern const struct floatformat floatformat_ia64_quad_little; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double (const struct floatformat *, const char *, double *); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double (const struct floatformat *, const double *, char *); + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +extern int +floatformat_is_valid (const struct floatformat *fmt, const char *from); + +#endif /* defined (FLOATFORMAT_H) */ +/* **** End of floatformat.h */ +/* **** m68k-dis.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table header for m680[01234]0/m6888[12]/m68851. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001, + 2003, 2004 Free Software Foundation, Inc. + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 1, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, + see . */ + +/* These are used as bit flags for the arch field in the m68k_opcode + structure. */ +#define _m68k_undef 0 +#define m68000 0x001 +#define m68008 m68000 /* Synonym for -m68000. otherwise unused. */ +#define m68010 0x002 +#define m68020 0x004 +#define m68030 0x008 +#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences; + gas will deal with the few differences. */ +#define m68040 0x010 +/* There is no 68050. */ +#define m68060 0x020 +#define m68881 0x040 +#define m68882 m68881 /* Synonym for -m68881. otherwise unused. */ +#define m68851 0x080 +#define cpu32 0x100 /* e.g., 68332 */ + +#define mcfmac 0x200 /* ColdFire MAC. */ +#define mcfemac 0x400 /* ColdFire EMAC. */ +#define cfloat 0x800 /* ColdFire FPU. */ +#define mcfhwdiv 0x1000 /* ColdFire hardware divide. */ + +#define mcfisa_a 0x2000 /* ColdFire ISA_A. */ +#define mcfisa_aa 0x4000 /* ColdFire ISA_A+. */ +#define mcfisa_b 0x8000 /* ColdFire ISA_B. */ +#define mcfusp 0x10000 /* ColdFire USP instructions. */ + +#define mcf5200 0x20000 +#define mcf5206e 0x40000 +#define mcf521x 0x80000 +#define mcf5249 0x100000 +#define mcf528x 0x200000 +#define mcf5307 0x400000 +#define mcf5407 0x800000 +#define mcf5470 0x1000000 +#define mcf5480 0x2000000 + + /* Handy aliases. */ +#define m68040up (m68040 | m68060) +#define m68030up (m68030 | m68040up) +#define m68020up (m68020 | m68030up) +#define m68010up (m68010 | cpu32 | m68020up) +#define m68000up (m68000 | m68010up) + +#define mfloat (m68881 | m68882 | m68040 | m68060) +#define mmmu (m68851 | m68030 | m68040 | m68060) + +/* The structure used to hold information for an opcode. */ + +struct m68k_opcode +{ + /* The opcode name. */ + const char *name; + /* The pseudo-size of the instruction(in bytes). Used to determine + number of bytes necessary to disassemble the instruction. */ + unsigned int size; + /* The opcode itself. */ + unsigned long opcode; + /* The mask used by the disassembler. */ + unsigned long match; + /* The arguments. */ + const char *args; + /* The architectures which support this opcode. */ + unsigned int arch; +}; + +/* The structure used to hold information for an opcode alias. */ + +struct m68k_opcode_alias +{ + /* The alias name. */ + const char *alias; + /* The instruction for which this is an alias. */ + const char *primary; +}; + +/* We store four bytes of opcode for all opcodes because that is the + most any of them need. The actual length of an instruction is + always at least 2 bytes, and is as much longer as necessary to hold + the operands it has. + + The match field is a mask saying which bits must match particular + opcode in order for an instruction to be an instance of that + opcode. + + The args field is a string containing two characters for each + operand of the instruction. The first specifies the kind of + operand; the second, the place it is stored. */ + +/* Kinds of operands: + Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+- + + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + a address register indirect only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + r either kind of register indirect only. Stored as 4 bits. + At the moment, used only for cas2 instruction. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + E the MAC ACC. No need to store, just as with CCR. + e the EMAC ACC[0123]. + G the MAC/EMAC MACSR. No need to store, just as with CCR. + g the EMAC ACCEXT{01,23}. + H the MASK. No need to store, just as with CCR. + i the MAC/EMAC scale factor. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 0x000 SFC Source Function Code reg [60, 40, 30, 20, 10] + 0x001 DFC Data Function Code reg [60, 40, 30, 20, 10] + 0x002 CACR Cache Control Register [60, 40, 30, 20, mcf] + 0x003 TC MMU Translation Control [60, 40] + 0x004 ITT0 Instruction Transparent + Translation reg 0 [60, 40] + 0x005 ITT1 Instruction Transparent + Translation reg 1 [60, 40] + 0x006 DTT0 Data Transparent + Translation reg 0 [60, 40] + 0x007 DTT1 Data Transparent + Translation reg 1 [60, 40] + 0x008 BUSCR Bus Control Register [60] + 0x800 USP User Stack Pointer [60, 40, 30, 20, 10] + 0x801 VBR Vector Base reg [60, 40, 30, 20, 10, mcf] + 0x802 CAAR Cache Address Register [ 30, 20] + 0x803 MSP Master Stack Pointer [ 40, 30, 20] + 0x804 ISP Interrupt Stack Pointer [ 40, 30, 20] + 0x805 MMUSR MMU Status reg [ 40] + 0x806 URP User Root Pointer [60, 40] + 0x807 SRP Supervisor Root Pointer [60, 40] + 0x808 PCR Processor Configuration reg [60] + 0xC00 ROMBAR ROM Base Address Register [520X] + 0xC04 RAMBAR0 RAM Base Address Register 0 [520X] + 0xC05 RAMBAR1 RAM Base Address Register 0 [520X] + 0xC0F MBAR0 RAM Base Address Register 0 [520X] + 0xC04 FLASHBAR FLASH Base Address Register [mcf528x] + 0xC05 RAMBAR Static RAM Base Address Register [mcf528x] + + L Register list of the type d0-d7/a0-a7 etc. + (New! Improved! Can also hold fp0-fp7, as well!) + The assembler tries to see if the registers match the insn by + looking at where the insn wants them stored. + + l Register list like L, but with all the bits reversed. + Used for going the other way. . . + + c cache identifier which may be "nc" for no cache, "ic" + for instruction cache, "dc" for data cache, or "bc" + for both caches. Used in cinv and cpush. Always + stored in position "d". + + u Any register, with ``upper'' or ``lower'' specification. Used + in the mac instructions with size word. + + The remainder are all stored as 6 bits using an address mode and a + register number; they differ in which addressing modes they match. + + * all (modes 0-6,7.0-4) + ~ alterable memory (modes 2-6,7.0,7.1) + (not 0,1,7.2-4) + % alterable (modes 0-6,7.0,7.1) + (not 7.2-4) + ; data (modes 0,2-6,7.0-4) + (not 1) + @ data, but not immediate (modes 0,2-6,7.0-3) + (not 1,7.4) + ! control (modes 2,5,6,7.0-3) + (not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1) + (not 0,1,3,4,7.2-4) + $ alterable data (modes 0,2-6,7.0,7.1) + (not 1,7.2-4) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1) + (not 1,3,4,7.2-4) + / control, or data register (modes 0,2,5,6,7.0-3) + (not 1,3,4,7.4) + > *save operands (modes 2,4,5,6,7.0,7.1) + (not 0,1,3,7.2-4) + < *restore operands (modes 2,3,5,6,7.0-3) + (not 0,1,4,7.4) + + coldfire move operands: + m (modes 0-4) + n (modes 5,7.2) + o (modes 6,7.0,7.1,7.3,7.4) + p (modes 0-5) + + coldfire bset/bclr/btst/mulsl/mulul operands: + q (modes 0,2-5) + v (modes 0,2-5,7.0,7.1) + b (modes 0,2-5,7.2) + w (modes 2-5,7.2) + y (modes 2,5) + z (modes 2,5,7.2) + x mov3q immediate operand. + 4 (modes 2,3,4,5) + */ + +/* For the 68851: */ +/* I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + 0 32 bit pmmu register + Possible values: + 000 TC Translation Control Register (68030, 68851) + + 1 16 bit pmmu register + 111 AC Access Control (68851) + + 2 8 bit pmmu register + 100 CAL Current Access Level (68851) + 101 VAL Validate Access Level (68851) + 110 SCC Stack Change Control (68851) + + 3 68030-only pmmu registers (32 bit) + 010 TT0 Transparent Translation reg 0 + (aka Access Control reg 0 -- AC0 -- on 68ec030) + 011 TT1 Transparent Translation reg 1 + (aka Access Control reg 1 -- AC1 -- on 68ec030) + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer (68851) + 010 SRP Supervisor Root Pointer (68030, 68851) + 011 CRP Cpu Root Pointer (68030, 68851) + + f function code register (68030, 68851) + 0 SFC + 1 DFC + + V VAL register only (68851) + + X BADx, BACx (16 bit) + 100 BAD Breakpoint Acknowledge Data (68851) + 101 BAC Breakpoint Acknowledge Control (68851) + + Y PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030) + Z PCSR (68851) + + | memory (modes 2-6, 7.*) + + t address test level (68030 only) + Stored as 3 bits, range 0-7. + Also used for breakpoint instruction now. + +*/ + +/* Places to put an operand, for non-general operands: + Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/ + + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + 9 second word, shifted 5 + D store in both place 1 and place 3; for divul and divsl. + B first word, low byte, for branch displacements + W second word (entire), for branch displacements + L second and third words (entire), for branch displacements + (also overloaded for move16) + b second word, low byte + w second word (entire) [variable word/long branch offset for dbra] + W second word (entire) (must be signed 16 bit value) + l second and third word (entire) + g variable branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + m For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word + and remaining 3 bits of register shifted 9 bits in first word. + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + n `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split + with MSB shifted 6 bits in first word and remaining 3 bits of + register shifted 9 bits in first word. No upper/lower + indication is done.) Use with `R' or `u' format. + o For M[S]ACw; 4 bits shifted 12 in second word (like `1'). + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + M For M[S]ACw; 4 bits in low bits of first word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + N For M[S]ACw; 4 bits in low bits of second word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + h shift indicator (scale factor), 1 bit shifted 10 in second word + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes + G EMAC accumulator, load (bit 4 2nd word, !bit8 first word) + H EMAC accumulator, non load (bit 4 2nd word, bit 8 first word) + F EMAC ACCx + f EMAC ACCy + I MAC/EMAC scale factor + / Like 's', but set 2nd word, bit 5 if trailing_ampersand set + ] first word, bit 10 +*/ + +extern const struct m68k_opcode m68k_opcodes[]; +extern const struct m68k_opcode_alias m68k_opcode_aliases[]; + +extern const int m68k_numopcodes, m68k_numaliases; + +/* **** End of m68k-opcode.h */ +/* **** m68k-dis.c from sourceware.org CVS 2005-08-14. */ +/* Print Motorola 68k instructions. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Local function prototypes. */ + +static const char * const fpcr_names[] = +{ + "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr", + "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr" +}; + +static const char *const reg_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", + "%ps", "%pc" +}; + +/* Name of register halves for MAC/EMAC. + Separate from reg_names since 'spu', 'fpl' look weird. */ +static const char *const reg_half_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%ps", "%pc" +}; + +/* Sign-extend an (unsigned char). */ +#if __STDC__ == 1 +#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch)) +#else +#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128) +#endif + +/* Get a 1 byte signed integer. */ +#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1])) + +/* Get a 2 byte signed integer. */ +#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000)) +#define NEXTWORD(p) \ + (p += 2, FETCH_DATA (info, p), \ + COERCE16 ((p[-2] << 8) + p[-1])) + +/* Get a 4 byte signed integer. */ +#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000) +#define NEXTLONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))) + +/* Get a 4 byte unsigned integer. */ +#define NEXTULONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) + +/* Get a single precision float. */ +#define NEXTSINGLE(val, p) \ + (p += 4, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val)) + +/* Get a double precision float. */ +#define NEXTDOUBLE(val, p) \ + (p += 8, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val)) + +/* Get an extended precision float. */ +#define NEXTEXTEND(val, p) \ + (p += 12, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val)) + +/* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ +#define NEXTPACKED(p) \ + (p += 12, FETCH_DATA (info, p), 0.0) + +/* Maximum length of an instruction. */ +#define MAXLEN 22 + +#include + +struct private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct private *priv = (struct private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +/* This function is used to print to the bit-bucket. */ +static int +dummy_printer (FILE *file ATTRIBUTE_UNUSED, + const char *format ATTRIBUTE_UNUSED, + ...) +{ + return 0; +} + +static void +dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED, + struct disassemble_info *info ATTRIBUTE_UNUSED) +{ +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (unsigned char *buffer, + int code, + int bits, + disassemble_info *info) +{ + int val = 0; + + switch (code) + { + case '/': /* MAC/EMAC mask bit. */ + val = buffer[3] >> 5; + break; + + case 'G': /* EMAC ACC load. */ + val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1); + break; + + case 'H': /* EMAC ACC !load. */ + val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1); + break; + + case ']': /* EMAC ACCEXT bit. */ + val = buffer[0] >> 2; + break; + + case 'I': /* MAC/EMAC scale factor. */ + val = buffer[2] >> 1; + break; + + case 'F': /* EMAC ACCx. */ + val = buffer[0] >> 1; + break; + + case 'f': + val = buffer[1]; + break; + + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + FETCH_DATA (info, buffer + 3); + val = (buffer[3] >> 4); + break; + + case 'C': + FETCH_DATA (info, buffer + 3); + val = buffer[3]; + break; + + case '1': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + case '9': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 5; + break; + + case 'e': + val = (buffer[1] >> 6); + break; + + case 'm': + val = (buffer[1] & 0x40 ? 0x8 : 0) + | ((buffer[0] >> 1) & 0x7) + | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'n': + val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7); + break; + + case 'o': + val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'M': + val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'N': + val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'h': + val = buffer[2] >> 2; + break; + + default: + abort (); + } + + switch (bits) + { + case 1: + return val & 1; + case 2: + return val & 3; + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Check if an EA is valid for a particular code. This is required + for the EMAC instructions since the type of source address determines + if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it + is a non-load EMAC instruction and the bits mean register Ry. + A similar case exists for the movem instructions where the register + mask is interpreted differently for different EAs. */ + +static bfd_boolean +m68k_valid_ea (char code, int val) +{ + int mode, mask; +#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \ + (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \ + | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11) + + switch (code) + { + case '*': + mask = M (1,1,1,1,1,1,1,1,1,1,1,1); + break; + case '~': + mask = M (0,0,1,1,1,1,1,1,1,0,0,0); + break; + case '%': + mask = M (1,1,1,1,1,1,1,1,1,0,0,0); + break; + case ';': + mask = M (1,0,1,1,1,1,1,1,1,1,1,1); + break; + case '@': + mask = M (1,0,1,1,1,1,1,1,1,1,1,0); + break; + case '!': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '&': + mask = M (0,0,1,0,0,1,1,1,1,0,0,0); + break; + case '$': + mask = M (1,0,1,1,1,1,1,1,1,0,0,0); + break; + case '?': + mask = M (1,0,1,0,0,1,1,1,1,0,0,0); + break; + case '/': + mask = M (1,0,1,0,0,1,1,1,1,1,1,0); + break; + case '|': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '>': + mask = M (0,0,1,0,1,1,1,1,1,0,0,0); + break; + case '<': + mask = M (0,0,1,1,0,1,1,1,1,1,1,0); + break; + case 'm': + mask = M (1,1,1,1,1,0,0,0,0,0,0,0); + break; + case 'n': + mask = M (0,0,0,0,0,1,0,0,0,1,0,0); + break; + case 'o': + mask = M (0,0,0,0,0,0,1,1,1,0,1,1); + break; + case 'p': + mask = M (1,1,1,1,1,1,0,0,0,0,0,0); + break; + case 'q': + mask = M (1,0,1,1,1,1,0,0,0,0,0,0); + break; + case 'v': + mask = M (1,0,1,1,1,1,0,1,1,0,0,0); + break; + case 'b': + mask = M (1,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'w': + mask = M (0,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'y': + mask = M (0,0,1,0,0,1,0,0,0,0,0,0); + break; + case 'z': + mask = M (0,0,1,0,0,1,0,0,0,1,0,0); + break; + case '4': + mask = M (0,0,1,1,1,1,0,0,0,0,0,0); + break; + default: + abort (); + } +#undef M + + mode = (val >> 3) & 7; + if (mode == 7) + mode += val & 7; + return (mask & (1 << mode)) != 0; +} + +/* Print a base register REGNO and displacement DISP, on INFO->STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (int regno, bfd_vma disp, disassemble_info *info) +{ + if (regno == -1) + { + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (disp, info); + } + else + { + char buf[50]; + + if (regno == -2) + (*info->fprintf_func) (info->stream, "@("); + else if (regno == -3) + (*info->fprintf_func) (info->stream, "%%zpc@("); + else + (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]); + + sprintf_vma (buf, disp); + (*info->fprintf_func) (info->stream, "%s", buf); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (int basereg, + unsigned char *p, + bfd_vma addr, + disassemble_info *info) +{ + int word; + static const char *const scales[] = { "", ":2", ":4", ":8" }; + bfd_vma base_disp; + bfd_vma outer_disp; + char buf[40]; + char vmabuf[50]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "%s:%c%s", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + base_disp = word & 0xff; + if ((base_disp & 0x80) != 0) + base_disp -= 0x100; + if (basereg == -1) + base_disp += addr; + print_base (basereg, base_disp, info); + (*info->fprintf_func) (info->stream, ",%s)", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + if (word & 0200) + { + if (basereg == -1) + basereg = -3; + else + basereg = -2; + } + if (word & 0100) + buf[0] = '\0'; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect). */ + if ((word & 7) == 0) + { + print_base (basereg, base_disp, info); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + print_base (basereg, base_disp, info); + if ((word & 4) == 0 && buf[0] != '\0') + { + (*info->fprintf_func) (info->stream, ",%s", buf); + buf[0] = '\0'; + } + sprintf_vma (vmabuf, outer_disp); + (*info->fprintf_func) (info->stream, ")@(%s", vmabuf); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + + return p; +} + +/* Returns number of bytes "eaten" by the operand, or + return -1 if an invalid operand was found, or -2 if + an opcode tabe error was found. + ADDR is the pc for this arg to be relative to. */ + +static int +print_insn_arg (const char *d, + unsigned char *buffer, + unsigned char *p0, + bfd_vma addr, + disassemble_info *info) +{ + int val = 0; + int place = d[1]; + unsigned char *p = p0; + int regno; + const char *regname; + unsigned char *p1; + double flval; + int flt_p; + bfd_signed_vma disp; + unsigned int uval; + + switch (*d) + { + case 'c': /* Cache identifier. */ + { + static const char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; + val = fetch_arg (buffer, place, 2, info); + (*info->fprintf_func) (info->stream, cacheFieldName[val]); + break; + } + + case 'a': /* Address register indirect only. Cf. case '+'. */ + { + (*info->fprintf_func) + (info->stream, + "%s@", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + } + + case '_': /* 32-bit absolute address for move16. */ + { + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + } + + case 'C': + (*info->fprintf_func) (info->stream, "%%ccr"); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%%sr"); + break; + + case 'U': + (*info->fprintf_func) (info->stream, "%%usp"); + break; + + case 'E': + (*info->fprintf_func) (info->stream, "%%acc"); + break; + + case 'G': + (*info->fprintf_func) (info->stream, "%%macsr"); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%%mask"); + break; + + case 'J': + { + /* FIXME: There's a problem here, different m68k processors call the + same address different names. This table can't get it right + because it doesn't know which processor it's disassembling for. */ + static const struct { const char *name; int value; } names[] + = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002}, + {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005}, + {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008}, + {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802}, + {"%msp", 0x803}, {"%isp", 0x804}, + {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */ + + /* Should we be calling this psr like we do in case 'Y'? */ + {"%mmusr",0x805}, + + {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}}; + + val = fetch_arg (buffer, place, 12, info); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + (*info->fprintf_func) (info->stream, "%s", names[regno].name); + break; + } + if (regno < 0) + (*info->fprintf_func) (info->stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3, info); + /* 0 means 8, except for the bkpt instruction... */ + if (val == 0 && d[1] != 's') + val = 8; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'x': + val = fetch_arg (buffer, place, 3, info); + /* 0 means -1. */ + if (val == 0) + val = -1; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'M': + if (place == 'h') + { + static const char *const scalefactor_name[] = { "<<", ">>" }; + val = fetch_arg (buffer, place, 1, info); + (*info->fprintf_func) (info->stream, scalefactor_name[val]); + } + else + { + val = fetch_arg (buffer, place, 8, info); + if (val & 0x80) + val = val - 0x100; + (*info->fprintf_func) (info->stream, "#%d", val); + } + break; + + case 'T': + val = fetch_arg (buffer, place, 4, info); + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'A': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info) + 010]); + break; + + case 'R': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 4, info)]); + break; + + case 'r': + regno = fetch_arg (buffer, place, 4, info); + if (regno > 7) + (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]); + else + (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]); + break; + + case 'F': + (*info->fprintf_func) + (info->stream, "%%fp%d", + fetch_arg (buffer, place, 3, info)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6, info); + if (val & 0x20) + (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]); + else + (*info->fprintf_func) (info->stream, "%d", val); + break; + + case '+': + (*info->fprintf_func) + (info->stream, "%s@+", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case '-': + (*info->fprintf_func) + (info->stream, "%s@-", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case 'k': + if (place == 'k') + (*info->fprintf_func) + (info->stream, "{%s}", + reg_names[fetch_arg (buffer, place, 3, info)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7, info); + if (val > 63) /* This is a signed constant. */ + val -= 128; + (*info->fprintf_func) (info->stream, "{#%d}", val); + } + else + return -2; + break; + + case '#': + case '^': + p1 = buffer + (*d == '#' ? 2 : 4); + if (place == 's') + val = fetch_arg (buffer, place, 4, info); + else if (place == 'C') + val = fetch_arg (buffer, place, 7, info); + else if (place == '8') + val = fetch_arg (buffer, place, 3, info); + else if (place == '3') + val = fetch_arg (buffer, place, 8, info); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w' || place == 'W') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + return -2; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + disp = NEXTBYTE (p); + else if (place == 'B') + disp = COERCE_SIGNED_CHAR (buffer[1]); + else if (place == 'w' || place == 'W') + disp = NEXTWORD (p); + else if (place == 'l' || place == 'L' || place == 'C') + disp = NEXTLONG (p); + else if (place == 'g') + { + disp = NEXTBYTE (buffer); + if (disp == 0) + disp = NEXTWORD (p); + else if (disp == -1) + disp = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset. */ + disp = NEXTLONG (p); + else + disp = NEXTWORD (p); + } + else + return -2; + + (*info->print_address_func) (addr + disp, info); + break; + + case 'd': + val = NEXTWORD (p); + (*info->fprintf_func) + (info->stream, "%s@(%d)", + reg_names[fetch_arg (buffer, place, 3, info) + 8], val); + break; + + case 's': + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'e': + val = fetch_arg(buffer, place, 2, info); + (*info->fprintf_func) (info->stream, "%%acc%d", val); + break; + + case 'g': + val = fetch_arg(buffer, place, 1, info); + (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23"); + break; + + case 'i': + val = fetch_arg(buffer, place, 2, info); + if (val == 1) + (*info->fprintf_func) (info->stream, "<<"); + else if (val == 3) + (*info->fprintf_func) (info->stream, ">>"); + else + return -1; + break; + + case 'I': + /* Get coprocessor ID... */ + val = fetch_arg (buffer, 'd', 3, info); + + if (val != 1) /* Unusual coprocessor ID? */ + (*info->fprintf_func) (info->stream, "(cpid=%d) ", val); + break; + + case '4': + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '$': + case '?': + case '/': + case '&': + case '|': + case '<': + case '>': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'v': + case 'b': + case 'w': + case 'y': + case 'z': + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6, info); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6, info); + + /* If the is invalid for *d, then reject this match. */ + if (!m68k_valid_ea (*d, val)) + return -1; + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + (*info->fprintf_func) (info->stream, "%s", reg_names[val]); + break; + + case 1: + (*info->fprintf_func) (info->stream, "%s", regname); + break; + + case 2: + (*info->fprintf_func) (info->stream, "%s@", regname); + break; + + case 3: + (*info->fprintf_func) (info->stream, "%s@+", regname); + break; + + case 4: + (*info->fprintf_func) (info->stream, "%s@-", regname); + break; + + case 5: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val); + break; + + case 6: + p = print_indexed (regno, p, addr, info); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + (*info->print_address_func) (val, info); + break; + + case 1: + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + + case 2: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (addr + val, info); + (*info->fprintf_func) (info->stream, ")"); + break; + + case 3: + p = print_indexed (-1, p, addr, info); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch (place) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + NEXTSINGLE (flval, p); + break; + + case 'F': + NEXTDOUBLE (flval, p); + break; + + case 'x': + NEXTEXTEND (flval, p); + break; + + case 'p': + flval = NEXTPACKED (p); + break; + + default: + return -1; + } + if (flt_p) /* Print a float? */ + (*info->fprintf_func) (info->stream, "#%g", flval); + else + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + default: + return -1; + } + } + + /* If place is '/', then this is the case of the mask bit for + mac/emac loads. Now that the arg has been printed, grab the + mask bit and if set, add a '&' to the arg. */ + if (place == '/') + { + val = fetch_arg (buffer, place, 1, info); + if (val) + info->fprintf_func (info->stream, "&"); + } + break; + + case 'L': + case 'l': + if (place == 'w') + { + char doneany; + p1 = buffer + 2; + val = NEXTWORD (p1); + /* Move the pointer ahead if this point is farther ahead + than the last. */ + p = p1 > p ? p1 : p; + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 16; ++regno) + if (val & (0x8000 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xffff; + doneany = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (1 << regno)) + { + int first_regno; + + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%s", reg_names[regno]); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%s", + reg_names[regno]); + } + } + else if (place == '3') + { + /* `fmovem' insn. */ + char doneany; + val = fetch_arg (buffer, place, 8, info); + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 8; ++regno) + if (val & (0x80 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xff; + doneany = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%%fp%d", regno); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%%fp%d", regno); + } + } + else if (place == '8') + { + /* fmoveml for FP status registers. */ + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, + info)]); + } + else + return -2; + break; + + case 'X': + place = '8'; + case 'Y': + case 'Z': + case 'W': + case '0': + case '1': + case '2': + case '3': + { + int val = fetch_arg (buffer, place, 5, info); + const char *name = 0; + + switch (val) + { + case 2: name = "%tt0"; break; + case 3: name = "%tt1"; break; + case 0x10: name = "%tc"; break; + case 0x11: name = "%drp"; break; + case 0x12: name = "%srp"; break; + case 0x13: name = "%crp"; break; + case 0x14: name = "%cal"; break; + case 0x15: name = "%val"; break; + case 0x16: name = "%scc"; break; + case 0x17: name = "%ac"; break; + case 0x18: name = "%psr"; break; + case 0x19: name = "%pcsr"; break; + case 0x1c: + case 0x1d: + { + int break_reg = ((buffer[3] >> 2) & 7); + + (*info->fprintf_func) + (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d", + break_reg); + } + break; + default: + (*info->fprintf_func) (info->stream, "", val); + } + if (name) + (*info->fprintf_func) (info->stream, "%s", name); + } + break; + + case 'f': + { + int fc = fetch_arg (buffer, place, 5, info); + + if (fc == 1) + (*info->fprintf_func) (info->stream, "%%dfc"); + else if (fc == 0) + (*info->fprintf_func) (info->stream, "%%sfc"); + else + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, _(""), fc); + } + break; + + case 'V': + (*info->fprintf_func) (info->stream, "%%val"); + break; + + case 't': + { + int level = fetch_arg (buffer, place, 3, info); + + (*info->fprintf_func) (info->stream, "%d", level); + } + break; + + case 'u': + { + short is_upper = 0; + int reg = fetch_arg (buffer, place, 5, info); + + if (reg & 0x10) + { + is_upper = 1; + reg &= 0xf; + } + (*info->fprintf_func) (info->stream, "%s%s", + reg_half_names[reg], + is_upper ? "u" : "l"); + } + break; + + default: + return -2; + } + + return p - p0; +} + +/* Try to match the current instruction to best and if so, return the + number of bytes consumed from the instruction stream, else zero. */ + +static int +match_insn_m68k (bfd_vma memaddr, + disassemble_info * info, + const struct m68k_opcode * best, + struct private * priv) +{ + unsigned char *save_p; + unsigned char *p; + const char *d; + + bfd_byte *buffer = priv->the_buffer; + fprintf_ftype save_printer = info->fprintf_func; + void (* save_print_address) (bfd_vma, struct disassemble_info *) + = info->print_address_func; + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Figure out how long the fixed-size portion of the instruction is. + The only place this is stored in the opcode table is + in the arguments--look for arguments which specify fields in the 2nd + or 3rd words of the instruction. */ + for (d = best->args; *d; d += 2) + { + /* I don't think it is necessary to be checking d[0] here; + I suspect all this could be moved to the case statement below. */ + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8') + p = buffer + 4; + } + + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) + p = buffer + 4; + + switch (d[1]) + { + case '1': + case '2': + case '3': + case '7': + case '8': + case '9': + case 'i': + if (p - buffer < 4) + p = buffer + 4; + break; + case '4': + case '5': + case '6': + if (p - buffer < 6) + p = buffer + 6; + break; + default: + break; + } + } + + /* pflusha is an exceptions. It takes no arguments but is two words + long. Recognize it by looking at the lower 16 bits of the mask. */ + if (p - buffer < 4 && (best->match & 0xFFFF) != 0) + p = buffer + 4; + + /* lpstop is another exception. It takes a one word argument but is + three words long. */ + if (p - buffer < 6 + && (best->match & 0xffff) == 0xffff + && best->args[0] == '#' + && best->args[1] == 'w') + { + /* Copy the one word argument into the usual location for a one + word argument, to simplify printing it. We can get away with + this because we know exactly what the second word is, and we + aren't going to print anything based on it. */ + p = buffer + 6; + FETCH_DATA (info, p); + buffer[2] = buffer[4]; + buffer[3] = buffer[5]; + } + + FETCH_DATA (info, p); + + d = best->args; + + save_p = p; + info->print_address_func = dummy_print_address; + info->fprintf_func = (fprintf_ftype) dummy_printer; + + /* We scan the operands twice. The first time we don't print anything, + but look for errors. */ + for (; *d; d += 2) + { + int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + + if (eaten >= 0) + p += eaten; + else if (eaten == -1) + { + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 0; + } + else + { + info->fprintf_func (info->stream, + /* xgettext:c-format */ + _("\n"), + best->name, best->args); + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 2; + } + } + + p = save_p; + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + + d = best->args; + + info->fprintf_func (info->stream, "%s", best->name); + + if (*d) + info->fprintf_func (info->stream, " "); + + while (*d) + { + p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + d += 2; + + if (*d && *(d - 2) != 'I' && *d != 'k') + info->fprintf_func (info->stream, ","); + } + + return p - buffer; +} + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on INFO->STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_m68k (bfd_vma memaddr, disassemble_info *info) +{ + int i; + const char *d; + unsigned int arch_mask; + struct private priv; + bfd_byte *buffer = priv.the_buffer; + int major_opcode; + static int numopcodes[16]; + static const struct m68k_opcode **opcodes[16]; + int val; + + if (!opcodes[0]) + { + /* Speed up the matching by sorting the opcode + table on the upper four bits of the opcode. */ + const struct m68k_opcode **opc_pointer[16]; + + /* First count how many opcodes are in each of the sixteen buckets. */ + for (i = 0; i < m68k_numopcodes; i++) + numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++; + + /* Then create a sorted table of pointers + that point into the unsorted table. */ + opc_pointer[0] = malloc (sizeof (struct m68k_opcode *) + * m68k_numopcodes); + opcodes[0] = opc_pointer[0]; + + for (i = 1; i < 16; i++) + { + opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1]; + opcodes[i] = opc_pointer[i]; + } + + for (i = 0; i < m68k_numopcodes; i++) + *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i]; + } + + info->private_data = (PTR) &priv; + /* Tell objdump to use two bytes per chunk + and six bytes per line for displaying raw data. */ + info->bytes_per_chunk = 2; + info->bytes_per_line = 6; + info->display_endian = BFD_ENDIAN_BIG; + priv.max_fetched = priv.the_buffer; + priv.insn_start = memaddr; + + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + switch (info->mach) + { + default: + case 0: + arch_mask = (unsigned int) -1; + break; + case bfd_mach_m68000: + arch_mask = m68000|m68881|m68851; + break; + case bfd_mach_m68008: + arch_mask = m68008|m68881|m68851; + break; + case bfd_mach_m68010: + arch_mask = m68010|m68881|m68851; + break; + case bfd_mach_m68020: + arch_mask = m68020|m68881|m68851; + break; + case bfd_mach_m68030: + arch_mask = m68030|m68881|m68851; + break; + case bfd_mach_m68040: + arch_mask = m68040|m68881|m68851; + break; + case bfd_mach_m68060: + arch_mask = m68060|m68881|m68851; + break; + case bfd_mach_mcf5200: + arch_mask = mcfisa_a; + break; + case bfd_mach_mcf521x: + case bfd_mach_mcf528x: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac; + break; + case bfd_mach_mcf5206e: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5249: + arch_mask = mcfisa_a|mcfhwdiv|mcfemac; + break; + case bfd_mach_mcf5307: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5407: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac; + break; + case bfd_mach_mcf547x: + case bfd_mach_mcf548x: + case bfd_mach_mcfv4e: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac; + break; + } + + FETCH_DATA (info, buffer + 2); + major_opcode = (buffer[0] >> 4) & 15; + + for (i = 0; i < numopcodes[major_opcode]; i++) + { + const struct m68k_opcode *opc = opcodes[major_opcode][i]; + unsigned long opcode = opc->opcode; + unsigned long match = opc->match; + + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + /* Only fetch the next two bytes if we need to. */ + && (((0xffff & match) == 0) + || + (FETCH_DATA (info, buffer + 4) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + ) + && (opc->arch & arch_mask) != 0) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = opc->args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == '\0') + for (d = opc->args; *d; d += 2) + if (d[1] == 't') + break; + + /* Don't match fmovel with more than one register; + wait for fmoveml. */ + if (*d == '\0') + { + for (d = opc->args; *d; d += 2) + { + if (d[0] == 's' && d[1] == '8') + { + val = fetch_arg (buffer, d[1], 3, info); + if ((val & (val - 1)) != 0) + break; + } + } + } + + if (*d == '\0') + if ((val = match_insn_m68k (memaddr, info, opc, & priv))) + return val; + } + } + + /* Handle undefined instructions. */ + info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; +} +/* **** End of m68k-dis.c */ +/* **** m68k-opc.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 1, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, + see . */ + +#define one(x) ((unsigned int) (x) << 16) +#define two(x, y) (((unsigned int) (x) << 16) + (y)) + +/* The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at + runtime. */ + +const struct m68k_opcode m68k_opcodes[] = +{ +{"abcd", 2, one(0140400), one(0170770), "DsDd", m68000up }, +{"abcd", 2, one(0140410), one(0170770), "-s-d", m68000up }, + +{"addaw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addal", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"addib", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addiw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, + +{"addqb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addqw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addql", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, + +/* The add opcode can generate the adda, addi, and addq instructions. */ +{"addb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addb", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addb", 2, one(0150000), one(0170700), ";bDd", m68000up }, +{"addb", 2, one(0150400), one(0170700), "Dd~b", m68000up }, +{"addw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addw", 2, one(0150100), one(0170700), "*wDd", m68000up }, +{"addw", 2, one(0150500), one(0170700), "Dd~w", m68000up }, +{"addl", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, +{"addl", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addl", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, +{"addl", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"addl", 2, one(0150200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"addl", 2, one(0150600), one(0170700), "Dd~l", m68000up | mcfisa_a }, + +{"addxb", 2, one(0150400), one(0170770), "DsDd", m68000up }, +{"addxb", 2, one(0150410), one(0170770), "-s-d", m68000up }, +{"addxw", 2, one(0150500), one(0170770), "DsDd", m68000up }, +{"addxw", 2, one(0150510), one(0170770), "-s-d", m68000up }, +{"addxl", 2, one(0150600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"addxl", 2, one(0150610), one(0170770), "-s-d", m68000up }, + +{"andib", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andib", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andiw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andiw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andi", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andi", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andi", 4, one(0001174), one(0177777), "#wSs", m68000up }, + +/* The and opcode can generate the andi instruction. */ +{"andb", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andb", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andb", 2, one(0140000), one(0170700), ";bDd", m68000up }, +{"andb", 2, one(0140400), one(0170700), "Dd~b", m68000up }, +{"andw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andw", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"andw", 2, one(0140500), one(0170700), "Dd~w", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andl", 2, one(0140200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"andl", 2, one(0140600), one(0170700), "Dd~l", m68000up | mcfisa_a }, +{"and", 4, one(0001100), one(0177700), "#w$w", m68000up }, +{"and", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"and", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"and", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"and", 2, one(0140500), one(0170700), "Dd~w", m68000up }, + +{"aslb", 2, one(0160400), one(0170770), "QdDs", m68000up }, +{"aslb", 2, one(0160440), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160500), one(0170770), "QdDs", m68000up }, +{"aslw", 2, one(0160540), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160700), one(0177700), "~s", m68000up }, +{"asll", 2, one(0160600), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asll", 2, one(0160640), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"asrb", 2, one(0160000), one(0170770), "QdDs", m68000up }, +{"asrb", 2, one(0160040), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160100), one(0170770), "QdDs", m68000up }, +{"asrw", 2, one(0160140), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160300), one(0177700), "~s", m68000up }, +{"asrl", 2, one(0160200), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asrl", 2, one(0160240), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"bhiw", 2, one(0061000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blsw", 2, one(0061400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bccw", 2, one(0062000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bcsw", 2, one(0062400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bnew", 2, one(0063000), one(0177777), "BW", m68000up | mcfisa_a }, +{"beqw", 2, one(0063400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvcw", 2, one(0064000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvsw", 2, one(0064400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bplw", 2, one(0065000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bmiw", 2, one(0065400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgew", 2, one(0066000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bltw", 2, one(0066400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgtw", 2, one(0067000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blew", 2, one(0067400), one(0177777), "BW", m68000up | mcfisa_a }, + +{"bhil", 2, one(0061377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blsl", 2, one(0061777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bccl", 2, one(0062377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bcsl", 2, one(0062777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bnel", 2, one(0063377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"beql", 2, one(0063777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvcl", 2, one(0064377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvsl", 2, one(0064777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bpll", 2, one(0065377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bmil", 2, one(0065777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgel", 2, one(0066377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bltl", 2, one(0066777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgtl", 2, one(0067377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blel", 2, one(0067777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, + +{"bhis", 2, one(0061000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blss", 2, one(0061400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bccs", 2, one(0062000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bcss", 2, one(0062400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bnes", 2, one(0063000), one(0177400), "BB", m68000up | mcfisa_a }, +{"beqs", 2, one(0063400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvcs", 2, one(0064000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvss", 2, one(0064400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bpls", 2, one(0065000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bmis", 2, one(0065400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bges", 2, one(0066000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blts", 2, one(0066400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bgts", 2, one(0067000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bles", 2, one(0067400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"jhi", 2, one(0061000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jls", 2, one(0061400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcc", 2, one(0062000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcs", 2, one(0062400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jne", 2, one(0063000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jeq", 2, one(0063400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvc", 2, one(0064000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvs", 2, one(0064400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jpl", 2, one(0065000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jmi", 2, one(0065400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jge", 2, one(0066000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jlt", 2, one(0066400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jgt", 2, one(0067000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jle", 2, one(0067400), one(0177400), "Bg", m68000up | mcfisa_a }, + +{"bchg", 2, one(0000500), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bchg", 4, one(0004100), one(0177700), "#b$s", m68000up }, +{"bchg", 4, one(0004100), one(0177700), "#bqs", mcfisa_a }, + +{"bclr", 2, one(0000600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bclr", 4, one(0004200), one(0177700), "#b$s", m68000up }, +{"bclr", 4, one(0004200), one(0177700), "#bqs", mcfisa_a }, + +{"bfchg", 4, two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfclr", 4, two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfexts", 4, two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfextu", 4, two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfffo", 4, two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfins", 4, two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up }, +{"bfset", 4, two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bftst", 4, two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up }, + +{"bgnd", 2, one(0045372), one(0177777), "", cpu32 }, + +{"bitrev", 2, one(0000300), one(0177770), "Ds", mcfisa_aa}, + +{"bkpt", 2, one(0044110), one(0177770), "ts", m68010up }, + +{"braw", 2, one(0060000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bral", 2, one(0060377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bras", 2, one(0060000), one(0177400), "BB", m68000up | mcfisa_a }, + +{"bset", 2, one(0000700), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bset", 2, one(0000700), one(0170700), "Ddvs", mcfisa_a }, +{"bset", 4, one(0004300), one(0177700), "#b$s", m68000up }, +{"bset", 4, one(0004300), one(0177700), "#bqs", mcfisa_a }, + +{"bsrw", 2, one(0060400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bsrl", 2, one(0060777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bsrs", 2, one(0060400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"btst", 2, one(0000400), one(0170700), "Dd;b", m68000up | mcfisa_a }, +{"btst", 4, one(0004000), one(0177700), "#b@s", m68000up }, +{"btst", 4, one(0004000), one(0177700), "#bqs", mcfisa_a }, + +{"byterev", 2, one(0001300), one(0177770), "Ds", mcfisa_aa}, + +{"callm", 4, one(0003300), one(0177700), "#b!s", m68020 }, + +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, + +{"casb", 4, two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casw", 4, two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casl", 4, two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, + +{"chk2b", 4, two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2w", 4, two(0001300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2l", 4, two(0002300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"chkl", 2, one(0040400), one(0170700), ";lDd", m68000up }, +{"chkw", 2, one(0040600), one(0170700), ";wDd", m68000up }, + +#define SCOPE_LINE (0x1 << 3) +#define SCOPE_PAGE (0x2 << 3) +#define SCOPE_ALL (0x3 << 3) + +{"cinva", 2, one(0xf400|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cinvl", 2, one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up }, +{"cinvp", 2, one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +{"cpusha", 2, one(0xf420|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cpushl", 2, one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a }, +{"cpushp", 2, one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +#undef SCOPE_LINE +#undef SCOPE_PAGE +#undef SCOPE_ALL + +{"clrb", 2, one(0041000), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrw", 2, one(0041100), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrl", 2, one(0041200), one(0177700), "$s", m68000up | mcfisa_a }, + +{"cmp2b", 4, two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2w", 4, two(0001300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2l", 4, two(0002300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"cmpaw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpal", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"cmpib", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpib", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpiw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpiw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpil", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpil", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, + +{"cmpmb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpmw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpml", 2, one(0130610), one(0170770), "+s+d", m68000up }, + +/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions. */ +{"cmpb", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpb", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), ";bDd", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), "*bDd", mcfisa_b }, +{"cmpw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpw", 2, one(0130100), one(0170700), "*wDd", m68000up | mcfisa_b }, +{"cmpl", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"cmpl", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpl", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, +{"cmpl", 2, one(0130610), one(0170770), "+s+d", m68000up }, +{"cmpl", 2, one(0130200), one(0170700), "*lDd", m68000up | mcfisa_a }, + +{"dbcc", 2, one(0052310), one(0177770), "DsBw", m68000up }, +{"dbcs", 2, one(0052710), one(0177770), "DsBw", m68000up }, +{"dbeq", 2, one(0053710), one(0177770), "DsBw", m68000up }, +{"dbf", 2, one(0050710), one(0177770), "DsBw", m68000up }, +{"dbge", 2, one(0056310), one(0177770), "DsBw", m68000up }, +{"dbgt", 2, one(0057310), one(0177770), "DsBw", m68000up }, +{"dbhi", 2, one(0051310), one(0177770), "DsBw", m68000up }, +{"dble", 2, one(0057710), one(0177770), "DsBw", m68000up }, +{"dbls", 2, one(0051710), one(0177770), "DsBw", m68000up }, +{"dblt", 2, one(0056710), one(0177770), "DsBw", m68000up }, +{"dbmi", 2, one(0055710), one(0177770), "DsBw", m68000up }, +{"dbne", 2, one(0053310), one(0177770), "DsBw", m68000up }, +{"dbpl", 2, one(0055310), one(0177770), "DsBw", m68000up }, +{"dbt", 2, one(0050310), one(0177770), "DsBw", m68000up }, +{"dbvc", 2, one(0054310), one(0177770), "DsBw", m68000up }, +{"dbvs", 2, one(0054710), one(0177770), "DsBw", m68000up }, + +{"divsw", 2, one(0100700), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divsl", 4, two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"divuw", 2, one(0100300), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divul", 4, two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"eorib", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorib", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eoriw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eoriw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eori", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eori", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eori", 4, one(0005100), one(0177700), "#w$s", m68000up }, + +/* The eor opcode can generate the eori instruction. */ +{"eorb", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorb", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eorb", 2, one(0130400), one(0170700), "Dd$s", m68000up }, +{"eorw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eorw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eorw", 2, one(0130500), one(0170700), "Dd$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eorl", 2, one(0130600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"eor", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eor", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eor", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up }, + +{"exg", 2, one(0140500), one(0170770), "DdDs", m68000up }, +{"exg", 2, one(0140510), one(0170770), "AdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "DdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "AsDd", m68000up }, + +{"extw", 2, one(0044200), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extl", 2, one(0044300), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extbl", 2, one(0044700), one(0177770), "Ds", m68020up|cpu32|mcfisa_a }, + +{"ff1", 2, one(0002300), one(0177770), "Ds", mcfisa_aa}, + +/* float stuff starts here */ + +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsp", 4, two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fabsx", 4, two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsp", 4, two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsabss", 4, two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabss", 4, two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdabsb", 4, two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsb", 4, two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up}, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up}, +{"fdabsl", 4, two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsl", 4, two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up}, +{"fdabsp", 4, two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up}, +{"fdabss", 4, two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabss", 4, two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up}, +{"fdabsw", 4, two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsw", 4, two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt", m68040up}, + +{"facosb", 4, two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"facosd", 4, two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"facosl", 4, two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"facosp", 4, two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"facoss", 4, two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"facosw", 4, two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"facosx", 4, two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddp", 4, two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddx", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"faddx", 4, two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddp", 4, two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddx", 4, two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsaddx", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdaddb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddb", 4, two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdaddl", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdaddl", 4, two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdaddp", 4, two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fasinb", 4, two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fasind", 4, two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fasinl", 4, two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fasinp", 4, two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fasins", 4, two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fasinw", 4, two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fasinx", 4, two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanb", 4, two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatand", 4, two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanl", 4, two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanp", 4, two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatans", 4, two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanw", 4, two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanx", 4, two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanhb", 4, two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatanhd", 4, two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanhl", 4, two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanhp", 4, two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatanhs", 4, two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanhw", 4, two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fbeq", 2, one(0xF081), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbf", 2, one(0xF080), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbge", 2, one(0xF093), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgl", 2, one(0xF096), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgle", 2, one(0xF097), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgt", 2, one(0xF092), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fble", 2, one(0xF095), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fblt", 2, one(0xF094), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbne", 2, one(0xF08E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnge", 2, one(0xF09C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngl", 2, one(0xF099), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngle", 2, one(0xF098), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngt", 2, one(0xF09D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnle", 2, one(0xF09A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnlt", 2, one(0xF09B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fboge", 2, one(0xF083), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogl", 2, one(0xF086), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogt", 2, one(0xF082), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbole", 2, one(0xF085), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbolt", 2, one(0xF084), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbor", 2, one(0xF087), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbseq", 2, one(0xF091), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsf", 2, one(0xF090), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsne", 2, one(0xF09E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbst", 2, one(0xF09F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbt", 2, one(0xF08F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbueq", 2, one(0xF089), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbuge", 2, one(0xF08B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbugt", 2, one(0xF08A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbule", 2, one(0xF08D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbult", 2, one(0xF08C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbun", 2, one(0xF088), one(0xF1FF), "IdBW", mfloat | cfloat }, + +{"fbeql", 2, one(0xF0C1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbfl", 2, one(0xF0C0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgel", 2, one(0xF0D3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgll", 2, one(0xF0D6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbglel", 2, one(0xF0D7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgtl", 2, one(0xF0D2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fblel", 2, one(0xF0D5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbltl", 2, one(0xF0D4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnel", 2, one(0xF0CE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngel", 2, one(0xF0DC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngll", 2, one(0xF0D9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnglel", 2, one(0xF0D8), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngtl", 2, one(0xF0DD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnlel", 2, one(0xF0DA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnltl", 2, one(0xF0DB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogel", 2, one(0xF0C3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogll", 2, one(0xF0C6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogtl", 2, one(0xF0C2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbolel", 2, one(0xF0C5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fboltl", 2, one(0xF0C4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fborl", 2, one(0xF0C7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbseql", 2, one(0xF0D1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsfl", 2, one(0xF0D0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsnel", 2, one(0xF0DE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbstl", 2, one(0xF0DF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbtl", 2, one(0xF0CF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbueql", 2, one(0xF0C9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugel", 2, one(0xF0CB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugtl", 2, one(0xF0CA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbulel", 2, one(0xF0CD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbultl", 2, one(0xF0CC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbunl", 2, one(0xF0C8), one(0xF1FF), "IdBC", mfloat | cfloat }, + +{"fjeq", 2, one(0xF081), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjf", 2, one(0xF080), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjge", 2, one(0xF093), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgl", 2, one(0xF096), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgle", 2, one(0xF097), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgt", 2, one(0xF092), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjle", 2, one(0xF095), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjlt", 2, one(0xF094), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjne", 2, one(0xF08E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnge", 2, one(0xF09C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngl", 2, one(0xF099), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngle", 2, one(0xF098), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngt", 2, one(0xF09D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnle", 2, one(0xF09A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnlt", 2, one(0xF09B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjoge", 2, one(0xF083), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogl", 2, one(0xF086), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogt", 2, one(0xF082), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjole", 2, one(0xF085), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjolt", 2, one(0xF084), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjor", 2, one(0xF087), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjseq", 2, one(0xF091), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsf", 2, one(0xF090), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsne", 2, one(0xF09E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjst", 2, one(0xF09F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjt", 2, one(0xF08F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjueq", 2, one(0xF089), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjuge", 2, one(0xF08B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjugt", 2, one(0xF08A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjule", 2, one(0xF08D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjult", 2, one(0xF08C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjun", 2, one(0xF088), one(0xF1BF), "IdBc", mfloat | cfloat }, + +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fcmpd", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpp", 4, two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpx", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcmpx", 4, two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fcosb", 4, two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcosd", 4, two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcosl", 4, two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcosp", 4, two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoss", 4, two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcosw", 4, two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcosx", 4, two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fcoshb", 4, two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcoshd", 4, two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcoshl", 4, two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcoshp", 4, two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoshs", 4, two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcoshw", 4, two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fdbeq", 4, two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbf", 4, two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbge", 4, two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgl", 4, two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgle", 4, two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgt", 4, two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdble", 4, two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdblt", 4, two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbne", 4, two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnge", 4, two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngl", 4, two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngle", 4, two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngt", 4, two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnle", 4, two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnlt", 4, two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdboge", 4, two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogl", 4, two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogt", 4, two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbole", 4, two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbolt", 4, two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbor", 4, two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbseq", 4, two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsf", 4, two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsne", 4, two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbst", 4, two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbt", 4, two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbueq", 4, two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbuge", 4, two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbugt", 4, two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbule", 4, two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbult", 4, two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbun", 4, two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, + +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivd", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivp", 4, two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivx", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fdivx", 4, two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivp", 4, two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivx", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsdivx", 4, two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivd", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivp", 4, two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivx", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fddivx", 4, two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fetoxb", 4, two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxd", 4, two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxl", 4, two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxp", 4, two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxs", 4, two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxw", 4, two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fetoxm1b", 4, two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxm1d", 4, two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxm1l", 4, two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxm1p", 4, two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxm1s", 4, two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxm1w", 4, two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetexpb", 4, two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetexpd", 4, two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetexpl", 4, two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetexpp", 4, two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetexps", 4, two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetexpw", 4, two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetmanb", 4, two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetmand", 4, two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetmanl", 4, two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetmanp", 4, two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetmans", 4, two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetmanw", 4, two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintp", 4, two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintx", 4, two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzp", 4, two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog10b", 4, two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog10d", 4, two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog10l", 4, two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog10p", 4, two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog10s", 4, two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog10w", 4, two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog10x", 4, two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog2b", 4, two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog2d", 4, two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog2l", 4, two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog2p", 4, two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog2s", 4, two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog2w", 4, two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog2x", 4, two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognb", 4, two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognd", 4, two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognl", 4, two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp", 4, two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flogns", 4, two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognw", 4, two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognx", 4, two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognp1b", 4, two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognp1d", 4, two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognp1l", 4, two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp1p", 4, two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flognp1s", 4, two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognp1w", 4, two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fmodb", 4, two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmodd", 4, two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmodl", 4, two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmodp", 4, two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmods", 4, two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmodw", 4, two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmodx", 4, two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmodx", 4, two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat }, +{"fmoved", 4, two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat }, +/* FIXME: the next two variants should not permit moving an address + register to anything but the floating point instruction register. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, + /* Move the FP control registers. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat }, +{"fmovep", 4, two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmovep", 4, two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat }, +{"fmovep", 4, two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovex", 4, two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat }, +{"fmovex", 4, two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fmovex", 4, two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat }, + +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoveb", 4, two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoved", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovel", 4, two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoves", 4, two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovew", 4, two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovex", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmovex", 4, two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsmovep", 4, two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoveb", 4, two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoved", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovel", 4, two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoves", 4, two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovew", 4, two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovex", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmovex", 4, two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdmovep", 4, two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fmovecrx", 4, two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, + +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat }, + +{"fmovemx", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, + +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +/* FIXME: In the next instruction, we should only permit %dn if the + target is a single register. We should only permit %an if the + target is a single %fpiar. */ +{"fmoveml", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat }, + +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat }, + +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovem", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, +{"fmovem", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat }, + +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmuld", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulp", 4, two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulx", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmulx", 4, two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulp", 4, two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulx", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmulx", 4, two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulp", 4, two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulx", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmulx", 4, two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegp", 4, two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fnegx", 4, two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegp", 4, two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegp", 4, two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fnop", 4, two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat }, + +{"fremb", 4, two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fremd", 4, two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"freml", 4, two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fremp", 4, two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"frems", 4, two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fremw", 4, two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fremx", 4, two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fremx", 4, two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"frestore", 2, one(0xF140), one(0xF1C0), "Ids", mfloat }, +{"fsave", 2, one(0xF100), one(0xF1C0), "Idzs", cfloat }, + +{"fscaleb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fscaled", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fscalel", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fscalep", 4, two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fscales", 4, two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fscalew", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fscalex", 4, two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fscalex", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +/* $ is necessary to prevent the assembler from using PC-relative. + If @ were used, "label: fseq label" could produce "ftrapeq", 2, + because "label" became "pc@label". */ +{"fseq", 4, two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsf", 4, two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsge", 4, two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgl", 4, two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgle", 4, two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgt", 4, two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsle", 4, two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fslt", 4, two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsne", 4, two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnge", 4, two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngl", 4, two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngle", 4, two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngt", 4, two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnle", 4, two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnlt", 4, two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsoge", 4, two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogl", 4, two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogt", 4, two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsole", 4, two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsolt", 4, two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsor", 4, two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsseq", 4, two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssf", 4, two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssne", 4, two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsst", 4, two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fst", 4, two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsueq", 4, two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsuge", 4, two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsugt", 4, two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsule", 4, two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsult", 4, two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsun", 4, two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, + +{"fsgldivb", 4, two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsgldivd", 4, two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsgldivl", 4, two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsgldivp", 4, two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsgldivs", 4, two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsgldivw", 4, two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsglmulb", 4, two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsglmuld", 4, two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsglmull", 4, two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsglmulp", 4, two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsglmuls", 4, two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsglmulw", 4, two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsinb", 4, two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsind", 4, two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinl", 4, two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinp", 4, two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsins", 4, two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinw", 4, two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinx", 4, two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsincosb", 4, two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat }, +{"fsincosd", 4, two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat }, +{"fsincosl", 4, two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat }, +{"fsincosp", 4, two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat }, +{"fsincoss", 4, two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat }, +{"fsincosw", 4, two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat }, + +{"fsinhb", 4, two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsinhd", 4, two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinhl", 4, two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinhp", 4, two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsinhs", 4, two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinhw", 4, two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtp", 4, two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtp", 4, two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtp", 4, two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubd", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubp", 4, two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsubx", 4, two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubb", 4, two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubp", 4, two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssubx", 4, two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsubb", 4, two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubb", 4, two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsubd", 4, two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsubl", 4, two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubl", 4, two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsubp", 4, two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsubs", 4, two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubs", 4, two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsubw", 4, two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubw", 4, two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"ftanb", 4, two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftand", 4, two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanl", 4, two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanp", 4, two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftans", 4, two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanw", 4, two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanx", 4, two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftanhb", 4, two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftanhd", 4, two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanhl", 4, two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanhp", 4, two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftanhs", 4, two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanhw", 4, two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftentoxb", 4, two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftentoxd", 4, two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftentoxl", 4, two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftentoxp", 4, two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftentoxs", 4, two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftentoxw", 4, two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftrapeq", 4, two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapf", 4, two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapge", 4, two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgl", 4, two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgle", 4, two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgt", 4, two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraple", 4, two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraplt", 4, two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapne", 4, two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnge", 4, two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngl", 4, two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngt", 4, two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnle", 4, two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnlt", 4, two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapoge", 4, two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogl", 4, two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogt", 4, two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapole", 4, two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapolt", 4, two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapor", 4, two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapseq", 4, two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsf", 4, two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsne", 4, two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapst", 4, two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapt", 4, two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapueq", 4, two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapuge", 4, two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapugt", 4, two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapule", 4, two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapult", 4, two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapun", 4, two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat }, + +{"ftrapeqw", 4, two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapfw", 4, two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgew", 4, two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglw", 4, two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgtw", 4, two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraplew", 4, two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapltw", 4, two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnew", 4, two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraporw", 4, two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsfw", 4, two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapstw", 4, two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraptw", 4, two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapunw", 4, two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, + +{"ftrapeql", 4, two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapfl", 4, two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgel", 4, two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgll", 4, two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgtl", 4, two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraplel", 4, two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapltl", 4, two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnel", 4, two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraporl", 4, two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsfl", 4, two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapstl", 4, two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraptl", 4, two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapunl", 4, two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, + +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat }, +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstd", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstp", 4, two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstx", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat }, +{"ftstx", 4, two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat }, + +{"ftwotoxb", 4, two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftwotoxd", 4, two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftwotoxl", 4, two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftwotoxp", 4, two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftwotoxs", 4, two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftwotoxw", 4, two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"halt", 2, one(0045310), one(0177777), "", m68060 | mcfisa_a }, + +{"illegal", 2, one(0045374), one(0177777), "", m68000up | mcfisa_a }, +{"intouch", 2, one(0xf428), one(0xfff8), "As", mcfisa_b }, + +{"jmp", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jra", 2, one(0060000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jra", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jbsr", 2, one(0060400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jbsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"lea", 2, one(0040700), one(0170700), "!sAd", m68000up | mcfisa_a }, + +{"lpstop", 6, two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 }, + +{"linkw", 4, one(0047120), one(0177770), "As#w", m68000up | mcfisa_a }, +{"linkl", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, +{"link", 4, one(0047120), one(0177770), "As#W", m68000up | mcfisa_a }, +{"link", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, + +{"lslb", 2, one(0160410), one(0170770), "QdDs", m68000up }, +{"lslb", 2, one(0160450), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0160510), one(0170770), "QdDs", m68000up }, +{"lslw", 2, one(0160550), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0161700), one(0177700), "~s", m68000up }, +{"lsll", 2, one(0160610), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsll", 2, one(0160650), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"lsrb", 2, one(0160010), one(0170770), "QdDs", m68000up }, +{"lsrb", 2, one(0160050), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0160110), one(0170770), "QdDs", m68000up }, +{"lsrw", 2, one(0160150), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0161300), one(0177700), "~s", m68000up }, +{"lsrl", 2, one(0160210), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsrl", 2, one(0160250), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac }, +{"macw", 4, two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac }, + +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +/* NOTE: The mcf5200 family programmer's reference manual does not + indicate the byte form of the movea instruction is invalid (as it + is on 68000 family cpus). However, experiments on the 5202 yeild + unexpected results. The value is copied, but it is not sign extended + (as is done with movea.w) and the top three bytes in the address + register are not disturbed. I don't know if this is the intended + behavior --- it could be a hole in instruction decoding (Motorola + decided not to trap all invalid instructions for performance reasons) + --- but I suspect that it is not. + + I reported this to Motorola ISD Technical Communications Support, + which replied that other coldfire assemblers reject movea.b. For + this reason I've decided to not allow moveab. + + jtc@cygnus.com - 97/01/24. */ + +{"moveal", 2, one(0020100), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"moveaw", 2, one(0030100), one(0170700), "*wAd", m68000up | mcfisa_a }, + +{"movclrl", 2, one(0xA1C0), one(0xf9f0), "eFRs", mcfemac }, + +{"movec", 4, one(0047173), one(0177777), "R1Jj", m68010up | mcfisa_a }, +{"movec", 4, one(0047173), one(0177777), "R1#j", m68010up | mcfisa_a }, +{"movec", 4, one(0047172), one(0177777), "JjR1", m68010up }, +{"movec", 4, one(0047172), one(0177777), "#jR1", m68010up }, + +{"movemw", 4, one(0044200), one(0177700), "Lw&s", m68000up }, +{"movemw", 4, one(0044240), one(0177770), "lw-s", m68000up }, +{"movemw", 4, one(0044200), one(0177700), "#w>s", m68000up }, +{"movemw", 4, one(0046200), one(0177700), "s", m68000up }, +{"moveml", 4, one(0046300), one(0177700), ",accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +{"mulsw", 2, one(0140700), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulsl", 4, two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"muluw", 2, one(0140300), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulul", 4, two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"nbcd", 2, one(0044000), one(0177700), "$s", m68000up }, + +{"negb", 2, one(0042000), one(0177700), "$s", m68000up }, +{"negw", 2, one(0042100), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "Ds", mcfisa_a}, + +{"negxb", 2, one(0040000), one(0177700), "$s", m68000up }, +{"negxw", 2, one(0040100), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "Ds", mcfisa_a}, + +{"nop", 2, one(0047161), one(0177777), "", m68000up | mcfisa_a}, + +{"notb", 2, one(0043000), one(0177700), "$s", m68000up }, +{"notw", 2, one(0043100), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "Ds", mcfisa_a}, + +{"orib", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orib", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"oriw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"oriw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"ori", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"ori", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"ori", 4, one(0000174), one(0177777), "#wSs", m68000up }, + +/* The or opcode can generate the ori instruction. */ +{"orb", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orb", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"orb", 2, one(0100000), one(0170700), ";bDd", m68000up }, +{"orb", 2, one(0100400), one(0170700), "Dd~s", m68000up }, +{"orw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"orw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"orw", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"orw", 2, one(0100500), one(0170700), "Dd~s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"orl", 2, one(0100200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"orl", 2, one(0100600), one(0170700), "Dd~s", m68000up | mcfisa_a }, +{"or", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"or", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"or", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"or", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"or", 2, one(0100500), one(0170700), "Dd~s", m68000up }, + +{"pack", 4, one(0100500), one(0170770), "DsDd#w", m68020up }, +{"pack", 4, one(0100510), one(0170770), "-s-d#w", m68020up }, + +{"pbac", 2, one(0xf087), one(0xffbf), "Bc", m68851 }, +{"pbacw", 2, one(0xf087), one(0xffff), "BW", m68851 }, +{"pbas", 2, one(0xf086), one(0xffbf), "Bc", m68851 }, +{"pbasw", 2, one(0xf086), one(0xffff), "BW", m68851 }, +{"pbbc", 2, one(0xf081), one(0xffbf), "Bc", m68851 }, +{"pbbcw", 2, one(0xf081), one(0xffff), "BW", m68851 }, +{"pbbs", 2, one(0xf080), one(0xffbf), "Bc", m68851 }, +{"pbbsw", 2, one(0xf080), one(0xffff), "BW", m68851 }, +{"pbcc", 2, one(0xf08f), one(0xffbf), "Bc", m68851 }, +{"pbccw", 2, one(0xf08f), one(0xffff), "BW", m68851 }, +{"pbcs", 2, one(0xf08e), one(0xffbf), "Bc", m68851 }, +{"pbcsw", 2, one(0xf08e), one(0xffff), "BW", m68851 }, +{"pbgc", 2, one(0xf08d), one(0xffbf), "Bc", m68851 }, +{"pbgcw", 2, one(0xf08d), one(0xffff), "BW", m68851 }, +{"pbgs", 2, one(0xf08c), one(0xffbf), "Bc", m68851 }, +{"pbgsw", 2, one(0xf08c), one(0xffff), "BW", m68851 }, +{"pbic", 2, one(0xf08b), one(0xffbf), "Bc", m68851 }, +{"pbicw", 2, one(0xf08b), one(0xffff), "BW", m68851 }, +{"pbis", 2, one(0xf08a), one(0xffbf), "Bc", m68851 }, +{"pbisw", 2, one(0xf08a), one(0xffff), "BW", m68851 }, +{"pblc", 2, one(0xf083), one(0xffbf), "Bc", m68851 }, +{"pblcw", 2, one(0xf083), one(0xffff), "BW", m68851 }, +{"pbls", 2, one(0xf082), one(0xffbf), "Bc", m68851 }, +{"pblsw", 2, one(0xf082), one(0xffff), "BW", m68851 }, +{"pbsc", 2, one(0xf085), one(0xffbf), "Bc", m68851 }, +{"pbscw", 2, one(0xf085), one(0xffff), "BW", m68851 }, +{"pbss", 2, one(0xf084), one(0xffbf), "Bc", m68851 }, +{"pbssw", 2, one(0xf084), one(0xffff), "BW", m68851 }, +{"pbwc", 2, one(0xf089), one(0xffbf), "Bc", m68851 }, +{"pbwcw", 2, one(0xf089), one(0xffff), "BW", m68851 }, +{"pbws", 2, one(0xf088), one(0xffbf), "Bc", m68851 }, +{"pbwsw", 2, one(0xf088), one(0xffff), "BW", m68851 }, + +{"pdbac", 4, two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbas", 4, two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbc", 4, two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbs", 4, two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcc", 4, two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcs", 4, two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgc", 4, two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgs", 4, two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbic", 4, two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbis", 4, two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdblc", 4, two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbls", 4, two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbsc", 4, two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbss", 4, two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbwc", 4, two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbws", 4, two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 }, + +{"pea", 2, one(0044100), one(0177700), "!s", m68000up|mcfisa_a }, + +{"pflusha", 2, one(0xf518), one(0xfff8), "", m68040up }, +{"pflusha", 4, two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 }, + +{"pflush", 4, two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 }, +{"pflush", 2, one(0xf508), one(0xfff8), "as", m68040up }, +{"pflush", 2, one(0xf508), one(0xfff8), "As", m68040up }, + +{"pflushan", 2, one(0xf510), one(0xfff8), "", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "as", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "As", m68040up }, + +{"pflushr", 4, two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 }, + +{"pflushs", 4, two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 }, + +{"ploadr", 4, two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, + +{"plpar", 2, one(0xf5c8), one(0xfff8), "as", m68060 }, +{"plpaw", 2, one(0xf588), one(0xfff8), "as", m68060 }, + +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 }, +{"pmove", 4, two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 }, +{"pmove", 4, two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 }, + +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "*l08", m68030 }, +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "|sW8", m68030 }, +{"pmovefd", 4, two(0xf000, 0x0900), two(0xffc0, 0xfbff), "*l38", m68030 }, + +{"prestore", 2, one(0xf140), one(0xffc0), "s", m68851 }, + +{"psac", 4, two(0xf040, 0x0007), two(0xffc0, 0xffff), "$s", m68851 }, +{"psas", 4, two(0xf040, 0x0006), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbc", 4, two(0xf040, 0x0001), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbs", 4, two(0xf040, 0x0000), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscc", 4, two(0xf040, 0x000f), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscs", 4, two(0xf040, 0x000e), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgc", 4, two(0xf040, 0x000d), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgs", 4, two(0xf040, 0x000c), two(0xffc0, 0xffff), "$s", m68851 }, +{"psic", 4, two(0xf040, 0x000b), two(0xffc0, 0xffff), "$s", m68851 }, +{"psis", 4, two(0xf040, 0x000a), two(0xffc0, 0xffff), "$s", m68851 }, +{"pslc", 4, two(0xf040, 0x0003), two(0xffc0, 0xffff), "$s", m68851 }, +{"psls", 4, two(0xf040, 0x0002), two(0xffc0, 0xffff), "$s", m68851 }, +{"pssc", 4, two(0xf040, 0x0005), two(0xffc0, 0xffff), "$s", m68851 }, +{"psss", 4, two(0xf040, 0x0004), two(0xffc0, 0xffff), "$s", m68851 }, +{"pswc", 4, two(0xf040, 0x0009), two(0xffc0, 0xffff), "$s", m68851 }, +{"psws", 4, two(0xf040, 0x0008), two(0xffc0, 0xffff), "$s", m68851 }, + +{"ptestr", 4, two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestr", 2, one(0xf568), one(0xfff8), "as", m68040 }, + +{"ptestw", 4, two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestw", 2, one(0xf548), one(0xfff8), "as", m68040 }, + +{"ptrapacw", 6, two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapacl", 6, two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapac", 4, two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapasw", 6, two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapasl", 6, two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapas", 4, two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbcw", 6, two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbcl", 6, two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbc", 4, two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbsw", 6, two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbsl", 6, two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbs", 4, two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapccw", 6, two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapccl", 6, two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcc", 4, two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapcsw", 6, two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapcsl", 6, two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcs", 4, two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgcw", 6, two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgcl", 6, two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgc", 4, two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgsw", 6, two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgsl", 6, two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgs", 4, two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapicw", 6, two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapicl", 6, two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapic", 4, two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapisw", 6, two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapisl", 6, two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapis", 4, two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplcw", 6, two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplcl", 6, two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 }, +{"ptraplc", 4, two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplsw", 6, two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplsl", 6, two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapls", 4, two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapscw", 6, two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapscl", 6, two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapsc", 4, two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapssw", 6, two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapssl", 6, two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapss", 4, two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwcw", 6, two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwcl", 6, two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapwc", 4, two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwsw", 6, two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwsl", 6, two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapws", 4, two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 }, + +{"pulse", 2, one(0045314), one(0177777), "", m68060 | mcfisa_a }, + +{"pvalid", 4, two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 }, +{"pvalid", 4, two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 }, + + /* FIXME: don't allow Dw==Dx. */ +{"remsl", 4, two(0x4c40, 0x0800), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, +{"remul", 4, two(0x4c40, 0x0000), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, + +{"reset", 2, one(0047160), one(0177777), "", m68000up }, + +{"rolb", 2, one(0160430), one(0170770), "QdDs", m68000up }, +{"rolb", 2, one(0160470), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0160530), one(0170770), "QdDs", m68000up }, +{"rolw", 2, one(0160570), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0163700), one(0177700), "~s", m68000up }, +{"roll", 2, one(0160630), one(0170770), "QdDs", m68000up }, +{"roll", 2, one(0160670), one(0170770), "DdDs", m68000up }, + +{"rorb", 2, one(0160030), one(0170770), "QdDs", m68000up }, +{"rorb", 2, one(0160070), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0160130), one(0170770), "QdDs", m68000up }, +{"rorw", 2, one(0160170), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0163300), one(0177700), "~s", m68000up }, +{"rorl", 2, one(0160230), one(0170770), "QdDs", m68000up }, +{"rorl", 2, one(0160270), one(0170770), "DdDs", m68000up }, + +{"roxlb", 2, one(0160420), one(0170770), "QdDs", m68000up }, +{"roxlb", 2, one(0160460), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0160520), one(0170770), "QdDs", m68000up }, +{"roxlw", 2, one(0160560), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0162700), one(0177700), "~s", m68000up }, +{"roxll", 2, one(0160620), one(0170770), "QdDs", m68000up }, +{"roxll", 2, one(0160660), one(0170770), "DdDs", m68000up }, + +{"roxrb", 2, one(0160020), one(0170770), "QdDs", m68000up }, +{"roxrb", 2, one(0160060), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0160120), one(0170770), "QdDs", m68000up }, +{"roxrw", 2, one(0160160), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0162300), one(0177700), "~s", m68000up }, +{"roxrl", 2, one(0160220), one(0170770), "QdDs", m68000up }, +{"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up }, + +{"rtd", 4, one(0047164), one(0177777), "#w", m68010up }, + +{"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a }, + +{"rtm", 2, one(0003300), one(0177760), "Rs", m68020 }, + +{"rtr", 2, one(0047167), one(0177777), "", m68000up }, + +{"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a }, + +{"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b }, + +{"sbcd", 2, one(0100400), one(0170770), "DsDd", m68000up }, +{"sbcd", 2, one(0100410), one(0170770), "-s-d", m68000up }, + +{"scc", 2, one(0052300), one(0177700), "$s", m68000up }, +{"scc", 2, one(0052300), one(0177700), "Ds", mcfisa_a }, +{"scs", 2, one(0052700), one(0177700), "$s", m68000up }, +{"scs", 2, one(0052700), one(0177700), "Ds", mcfisa_a }, +{"seq", 2, one(0053700), one(0177700), "$s", m68000up }, +{"seq", 2, one(0053700), one(0177700), "Ds", mcfisa_a }, +{"sf", 2, one(0050700), one(0177700), "$s", m68000up }, +{"sf", 2, one(0050700), one(0177700), "Ds", mcfisa_a }, +{"sge", 2, one(0056300), one(0177700), "$s", m68000up }, +{"sge", 2, one(0056300), one(0177700), "Ds", mcfisa_a }, +{"sgt", 2, one(0057300), one(0177700), "$s", m68000up }, +{"sgt", 2, one(0057300), one(0177700), "Ds", mcfisa_a }, +{"shi", 2, one(0051300), one(0177700), "$s", m68000up }, +{"shi", 2, one(0051300), one(0177700), "Ds", mcfisa_a }, +{"sle", 2, one(0057700), one(0177700), "$s", m68000up }, +{"sle", 2, one(0057700), one(0177700), "Ds", mcfisa_a }, +{"sls", 2, one(0051700), one(0177700), "$s", m68000up }, +{"sls", 2, one(0051700), one(0177700), "Ds", mcfisa_a }, +{"slt", 2, one(0056700), one(0177700), "$s", m68000up }, +{"slt", 2, one(0056700), one(0177700), "Ds", mcfisa_a }, +{"smi", 2, one(0055700), one(0177700), "$s", m68000up }, +{"smi", 2, one(0055700), one(0177700), "Ds", mcfisa_a }, +{"sne", 2, one(0053300), one(0177700), "$s", m68000up }, +{"sne", 2, one(0053300), one(0177700), "Ds", mcfisa_a }, +{"spl", 2, one(0055300), one(0177700), "$s", m68000up }, +{"spl", 2, one(0055300), one(0177700), "Ds", mcfisa_a }, +{"st", 2, one(0050300), one(0177700), "$s", m68000up }, +{"st", 2, one(0050300), one(0177700), "Ds", mcfisa_a }, +{"svc", 2, one(0054300), one(0177700), "$s", m68000up }, +{"svc", 2, one(0054300), one(0177700), "Ds", mcfisa_a }, +{"svs", 2, one(0054700), one(0177700), "$s", m68000up }, +{"svs", 2, one(0054700), one(0177700), "Ds", mcfisa_a }, + +{"stop", 4, one(0047162), one(0177777), "#w", m68000up | mcfisa_a }, + +{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa}, + +{"subal", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subaw", 2, one(0110300), one(0170700), "*wAd", m68000up }, + +{"subib", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subiw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, + +{"subqb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subqw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subql", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, + +/* The sub opcode can generate the suba, subi, and subq instructions. */ +{"subb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subb", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subb", 2, one(0110000), one(0170700), ";bDd", m68000up }, +{"subb", 2, one(0110400), one(0170700), "Dd~s", m68000up }, +{"subw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subw", 2, one(0110300), one(0170700), "*wAd", m68000up }, +{"subw", 2, one(0110100), one(0170700), "*wDd", m68000up }, +{"subw", 2, one(0110500), one(0170700), "Dd~s", m68000up }, +{"subl", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, +{"subl", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subl", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, +{"subl", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subl", 2, one(0110200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"subl", 2, one(0110600), one(0170700), "Dd~s", m68000up | mcfisa_a }, + +{"subxb", 2, one(0110400), one(0170770), "DsDd", m68000up }, +{"subxb", 2, one(0110410), one(0170770), "-s-d", m68000up }, +{"subxw", 2, one(0110500), one(0170770), "DsDd", m68000up }, +{"subxw", 2, one(0110510), one(0170770), "-s-d", m68000up }, +{"subxl", 2, one(0110600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"subxl", 2, one(0110610), one(0170770), "-s-d", m68000up }, + +{"swap", 2, one(0044100), one(0177770), "Ds", m68000up | mcfisa_a }, + +/* swbeg and swbegl are magic constants used on sysV68. The compiler + generates them before a switch table. They tell the debugger and + disassembler that a switch table follows. The parameter is the + number of elements in the table. swbeg means that the entries in + the table are word (2 byte) sized, and swbegl means that the + entries in the table are longword (4 byte) sized. */ +{"swbeg", 4, one(0045374), one(0177777), "#w", m68000up | mcfisa_a }, +{"swbegl", 6, one(0045375), one(0177777), "#l", m68000up | mcfisa_a }, + +{"tas", 2, one(0045300), one(0177700), "$s", m68000up | mcfisa_b}, + +#define TBL1(name,insn_size,signed,round,size) \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400), \ + two(0177700,0107777), "!sD1", cpu32 }, \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)), \ + two(0177770,0107770), "DsD3D1", cpu32 } +#define TBL(name1, name2, name3, s, r) \ + TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2) +TBL("tblsb", "tblsw", "tblsl", 2, 1), +TBL("tblsnb", "tblsnw", "tblsnl", 2, 0), +TBL("tblub", "tbluw", "tblul", 0, 1), +TBL("tblunb", "tblunw", "tblunl", 0, 0), + +{"trap", 2, one(0047100), one(0177760), "Ts", m68000up | mcfisa_a }, + +{"trapcc", 2, one(0052374), one(0177777), "", m68020up | cpu32 }, +{"trapcs", 2, one(0052774), one(0177777), "", m68020up | cpu32 }, +{"trapeq", 2, one(0053774), one(0177777), "", m68020up | cpu32 }, +{"trapf", 2, one(0050774), one(0177777), "", m68020up | cpu32 | mcfisa_a }, +{"trapge", 2, one(0056374), one(0177777), "", m68020up | cpu32 }, +{"trapgt", 2, one(0057374), one(0177777), "", m68020up | cpu32 }, +{"traphi", 2, one(0051374), one(0177777), "", m68020up | cpu32 }, +{"traple", 2, one(0057774), one(0177777), "", m68020up | cpu32 }, +{"trapls", 2, one(0051774), one(0177777), "", m68020up | cpu32 }, +{"traplt", 2, one(0056774), one(0177777), "", m68020up | cpu32 }, +{"trapmi", 2, one(0055774), one(0177777), "", m68020up | cpu32 }, +{"trapne", 2, one(0053374), one(0177777), "", m68020up | cpu32 }, +{"trappl", 2, one(0055374), one(0177777), "", m68020up | cpu32 }, +{"trapt", 2, one(0050374), one(0177777), "", m68020up | cpu32 }, +{"trapvc", 2, one(0054374), one(0177777), "", m68020up | cpu32 }, +{"trapvs", 2, one(0054774), one(0177777), "", m68020up | cpu32 }, + +{"trapccw", 4, one(0052372), one(0177777), "#w", m68020up|cpu32 }, +{"trapcsw", 4, one(0052772), one(0177777), "#w", m68020up|cpu32 }, +{"trapeqw", 4, one(0053772), one(0177777), "#w", m68020up|cpu32 }, +{"trapfw", 4, one(0050772), one(0177777), "#w", m68020up|cpu32|mcfisa_a}, +{"trapgew", 4, one(0056372), one(0177777), "#w", m68020up|cpu32 }, +{"trapgtw", 4, one(0057372), one(0177777), "#w", m68020up|cpu32 }, +{"traphiw", 4, one(0051372), one(0177777), "#w", m68020up|cpu32 }, +{"traplew", 4, one(0057772), one(0177777), "#w", m68020up|cpu32 }, +{"traplsw", 4, one(0051772), one(0177777), "#w", m68020up|cpu32 }, +{"trapltw", 4, one(0056772), one(0177777), "#w", m68020up|cpu32 }, +{"trapmiw", 4, one(0055772), one(0177777), "#w", m68020up|cpu32 }, +{"trapnew", 4, one(0053372), one(0177777), "#w", m68020up|cpu32 }, +{"trapplw", 4, one(0055372), one(0177777), "#w", m68020up|cpu32 }, +{"traptw", 4, one(0050372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvcw", 4, one(0054372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvsw", 4, one(0054772), one(0177777), "#w", m68020up|cpu32 }, + +{"trapccl", 6, one(0052373), one(0177777), "#l", m68020up|cpu32 }, +{"trapcsl", 6, one(0052773), one(0177777), "#l", m68020up|cpu32 }, +{"trapeql", 6, one(0053773), one(0177777), "#l", m68020up|cpu32 }, +{"trapfl", 6, one(0050773), one(0177777), "#l", m68020up|cpu32|mcfisa_a}, +{"trapgel", 6, one(0056373), one(0177777), "#l", m68020up|cpu32 }, +{"trapgtl", 6, one(0057373), one(0177777), "#l", m68020up|cpu32 }, +{"traphil", 6, one(0051373), one(0177777), "#l", m68020up|cpu32 }, +{"traplel", 6, one(0057773), one(0177777), "#l", m68020up|cpu32 }, +{"traplsl", 6, one(0051773), one(0177777), "#l", m68020up|cpu32 }, +{"trapltl", 6, one(0056773), one(0177777), "#l", m68020up|cpu32 }, +{"trapmil", 6, one(0055773), one(0177777), "#l", m68020up|cpu32 }, +{"trapnel", 6, one(0053373), one(0177777), "#l", m68020up|cpu32 }, +{"trappll", 6, one(0055373), one(0177777), "#l", m68020up|cpu32 }, +{"traptl", 6, one(0050373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvcl", 6, one(0054373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvsl", 6, one(0054773), one(0177777), "#l", m68020up|cpu32 }, + +{"trapv", 2, one(0047166), one(0177777), "", m68000up }, + +{"tstb", 2, one(0045000), one(0177700), ";b", m68020up|cpu32|mcfisa_a }, +{"tstb", 2, one(0045000), one(0177700), "$b", m68000up }, +{"tstw", 2, one(0045100), one(0177700), "*w", m68020up|cpu32|mcfisa_a }, +{"tstw", 2, one(0045100), one(0177700), "$w", m68000up }, +{"tstl", 2, one(0045200), one(0177700), "*l", m68020up|cpu32|mcfisa_a }, +{"tstl", 2, one(0045200), one(0177700), "$l", m68000up }, + +{"unlk", 2, one(0047130), one(0177770), "As", m68000up | mcfisa_a }, + +{"unpk", 4, one(0100600), one(0170770), "DsDd#w", m68020up }, +{"unpk", 4, one(0100610), one(0170770), "-s-d#w", m68020up }, + +{"wddatab", 2, one(0175400), one(0177700), "~s", mcfisa_a }, +{"wddataw", 2, one(0175500), one(0177700), "~s", mcfisa_a }, +{"wddatal", 2, one(0175600), one(0177700), "~s", mcfisa_a }, + +{"wdebug", 4, two(0175720, 03), two(0177770, 0xffff), "as", mcfisa_a }, +{"wdebug", 4, two(0175750, 03), two(0177770, 0xffff), "ds", mcfisa_a }, +}; + +const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0]; + +/* These aliases used to be in the above table, each one duplicating + all of the entries for its primary exactly. This table was + constructed by mechanical processing of the opcode table, with a + small number of tweaks done by hand. There are probably a lot more + aliases above that could be moved down here, except for very minor + differences. */ + +const struct m68k_opcode_alias m68k_opcode_aliases[] = +{ + { "add", "addw", }, + { "adda", "addaw", }, + { "addi", "addiw", }, + { "addq", "addqw", }, + { "addx", "addxw", }, + { "asl", "aslw", }, + { "asr", "asrw", }, + { "bhi", "bhiw", }, + { "bls", "blsw", }, + { "bcc", "bccw", }, + { "bcs", "bcsw", }, + { "bne", "bnew", }, + { "beq", "beqw", }, + { "bvc", "bvcw", }, + { "bvs", "bvsw", }, + { "bpl", "bplw", }, + { "bmi", "bmiw", }, + { "bge", "bgew", }, + { "blt", "bltw", }, + { "bgt", "bgtw", }, + { "ble", "blew", }, + { "bra", "braw", }, + { "bsr", "bsrw", }, + { "bhib", "bhis", }, + { "blsb", "blss", }, + { "bccb", "bccs", }, + { "bcsb", "bcss", }, + { "bneb", "bnes", }, + { "beqb", "beqs", }, + { "bvcb", "bvcs", }, + { "bvsb", "bvss", }, + { "bplb", "bpls", }, + { "bmib", "bmis", }, + { "bgeb", "bges", }, + { "bltb", "blts", }, + { "bgtb", "bgts", }, + { "bleb", "bles", }, + { "brab", "bras", }, + { "bsrb", "bsrs", }, + { "bhs", "bccw" }, + { "bhss", "bccs" }, + { "bhsb", "bccs" }, + { "bhsw", "bccw" }, + { "bhsl", "bccl" }, + { "blo", "bcsw" }, + { "blos", "bcss" }, + { "blob", "bcss" }, + { "blow", "bcsw" }, + { "blol", "bcsl" }, + { "br", "braw", }, + { "brs", "bras", }, + { "brb", "bras", }, + { "brw", "braw", }, + { "brl", "bral", }, + { "jfnlt", "bcc", }, /* Apparently a sun alias. */ + { "jfngt", "ble", }, /* Apparently a sun alias. */ + { "jfeq", "beqs", }, /* Apparently a sun alias. */ + { "bchgb", "bchg", }, + { "bchgl", "bchg", }, + { "bclrb", "bclr", }, + { "bclrl", "bclr", }, + { "bsetb", "bset", }, + { "bsetl", "bset", }, + { "btstb", "btst", }, + { "btstl", "btst", }, + { "cas2", "cas2w", }, + { "cas", "casw", }, + { "chk2", "chk2w", }, + { "chk", "chkw", }, + { "clr", "clrw", }, + { "cmp2", "cmp2w", }, + { "cmpa", "cmpaw", }, + { "cmpi", "cmpiw", }, + { "cmpm", "cmpmw", }, + { "cmp", "cmpw", }, + { "dbccw", "dbcc", }, + { "dbcsw", "dbcs", }, + { "dbeqw", "dbeq", }, + { "dbfw", "dbf", }, + { "dbgew", "dbge", }, + { "dbgtw", "dbgt", }, + { "dbhiw", "dbhi", }, + { "dblew", "dble", }, + { "dblsw", "dbls", }, + { "dbltw", "dblt", }, + { "dbmiw", "dbmi", }, + { "dbnew", "dbne", }, + { "dbplw", "dbpl", }, + { "dbtw", "dbt", }, + { "dbvcw", "dbvc", }, + { "dbvsw", "dbvs", }, + { "dbhs", "dbcc", }, + { "dbhsw", "dbcc", }, + { "dbra", "dbf", }, + { "dbraw", "dbf", }, + { "tdivsl", "divsl", }, + { "divs", "divsw", }, + { "divu", "divuw", }, + { "ext", "extw", }, + { "extbw", "extw", }, + { "extwl", "extl", }, + { "fbneq", "fbne", }, + { "fbsneq", "fbsne", }, + { "fdbneq", "fdbne", }, + { "fdbsneq", "fdbsne", }, + { "fmovecr", "fmovecrx", }, + { "fmovm", "fmovem", }, + { "fsneq", "fsne", }, + { "fssneq", "fssne", }, + { "ftrapneq", "ftrapne", }, + { "ftrapsneq", "ftrapsne", }, + { "fjneq", "fjne", }, + { "fjsneq", "fjsne", }, + { "jmpl", "jmp", }, + { "jmps", "jmp", }, + { "jsrl", "jsr", }, + { "jsrs", "jsr", }, + { "leal", "lea", }, + { "lsl", "lslw", }, + { "lsr", "lsrw", }, + { "mac", "macw" }, + { "movea", "moveaw", }, + { "movem", "movemw", }, + { "movml", "moveml", }, + { "movmw", "movemw", }, + { "movm", "movemw", }, + { "movep", "movepw", }, + { "movpw", "movepw", }, + { "moves", "movesw" }, + { "muls", "mulsw", }, + { "mulu", "muluw", }, + { "msac", "msacw" }, + { "nbcdb", "nbcd" }, + { "neg", "negw", }, + { "negx", "negxw", }, + { "not", "notw", }, + { "peal", "pea", }, + { "rol", "rolw", }, + { "ror", "rorw", }, + { "roxl", "roxlw", }, + { "roxr", "roxrw", }, + { "sats", "satsl", }, + { "sbcdb", "sbcd", }, + { "sccb", "scc", }, + { "scsb", "scs", }, + { "seqb", "seq", }, + { "sfb", "sf", }, + { "sgeb", "sge", }, + { "sgtb", "sgt", }, + { "shib", "shi", }, + { "sleb", "sle", }, + { "slsb", "sls", }, + { "sltb", "slt", }, + { "smib", "smi", }, + { "sneb", "sne", }, + { "splb", "spl", }, + { "stb", "st", }, + { "svcb", "svc", }, + { "svsb", "svs", }, + { "sfge", "sge", }, + { "sfgt", "sgt", }, + { "sfle", "sle", }, + { "sflt", "slt", }, + { "sfneq", "sne", }, + { "suba", "subaw", }, + { "subi", "subiw", }, + { "subq", "subqw", }, + { "sub", "subw", }, + { "subx", "subxw", }, + { "swapw", "swap", }, + { "tasb", "tas", }, + { "tpcc", "trapcc", }, + { "tcc", "trapcc", }, + { "tst", "tstw", }, + { "jbra", "jra", }, + { "jbhi", "jhi", }, + { "jbls", "jls", }, + { "jbcc", "jcc", }, + { "jbcs", "jcs", }, + { "jbne", "jne", }, + { "jbeq", "jeq", }, + { "jbvc", "jvc", }, + { "jbvs", "jvs", }, + { "jbpl", "jpl", }, + { "jbmi", "jmi", }, + { "jbge", "jge", }, + { "jblt", "jlt", }, + { "jbgt", "jgt", }, + { "jble", "jle", }, + { "movql", "moveq", }, + { "moveql", "moveq", }, + { "movl", "movel", }, + { "movq", "moveq", }, + { "moval", "moveal", }, + { "movaw", "moveaw", }, + { "movb", "moveb", }, + { "movc", "movec", }, + { "movecl", "movec", }, + { "movpl", "movepl", }, + { "movw", "movew", }, + { "movsb", "movesb", }, + { "movsl", "movesl", }, + { "movsw", "movesw", }, + { "mov3q", "mov3ql", }, + + { "tdivul", "divul", }, /* For m68k-svr4. */ + { "fmovb", "fmoveb", }, + { "fsmovb", "fsmoveb", }, + { "fdmovb", "fdmoveb", }, + { "fmovd", "fmoved", }, + { "fsmovd", "fsmoved", }, + { "fmovl", "fmovel", }, + { "fsmovl", "fsmovel", }, + { "fdmovl", "fdmovel", }, + { "fmovp", "fmovep", }, + { "fsmovp", "fsmovep", }, + { "fdmovp", "fdmovep", }, + { "fmovs", "fmoves", }, + { "fsmovs", "fsmoves", }, + { "fdmovs", "fdmoves", }, + { "fmovw", "fmovew", }, + { "fsmovw", "fsmovew", }, + { "fdmovw", "fdmovew", }, + { "fmovx", "fmovex", }, + { "fsmovx", "fsmovex", }, + { "fdmovx", "fdmovex", }, + { "fmovcr", "fmovecr", }, + { "fmovcrx", "fmovecrx", }, + { "ftestb", "ftstb", }, + { "ftestd", "ftstd", }, + { "ftestl", "ftstl", }, + { "ftestp", "ftstp", }, + { "ftests", "ftsts", }, + { "ftestw", "ftstw", }, + { "ftestx", "ftstx", }, + + { "bitrevl", "bitrev", }, + { "byterevl", "byterev", }, + { "ff1l", "ff1", }, + +}; + +const int m68k_numaliases = + sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0]; +/* **** End of m68k-opc.c */ +/* **** floatformat.c from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +/* This is needed to pick up the NAN macro on some systems. */ +//#define _GNU_SOURCE + +#ifndef INFINITY +#ifdef HUGE_VAL +#define INFINITY HUGE_VAL +#else +#define INFINITY (1.0 / 0.0) +#endif +#endif + +#ifndef NAN +#define NAN (0.0 / 0.0) +#endif + +static unsigned long get_field (const unsigned char *, + enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int); +static int floatformat_always_valid (const struct floatformat *fmt, + const char *from); + +static int +floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, + const char *from ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +/* floatformats for IEEE single and double, big and little endian. */ +const struct floatformat floatformat_ieee_single_big = +{ + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_single_little = +{ + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_big = +{ + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_little = +{ + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_little", + floatformat_always_valid +}; + +/* floatformat for IEEE double, little endian byte order, with big endian word + ordering, as on the ARM. */ + +const struct floatformat floatformat_ieee_double_littlebyte_bigword = +{ + floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_littlebyte_bigword", + floatformat_always_valid +}; + +static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from); + +static int +floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from) +{ + /* In the i387 double-extended format, if the exponent is all ones, + then the integer bit must be set. If the exponent is neither 0 + nor ~0, the intbit must also be set. Only if the exponent is + zero can it be zero, and then it must be zero. */ + unsigned long exponent, int_bit; + const unsigned char *ufrom = (const unsigned char *) from; + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->man_start, 1); + + if ((exponent == 0) != (int_bit == 0)) + return 0; + else + return 1; +} + +const struct floatformat floatformat_i387_ext = +{ + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_i387_ext", + floatformat_i387_ext_is_valid +}; +const struct floatformat floatformat_m68881_ext = +{ + /* Note that the bits from 16 to 31 are unused. */ + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_m68881_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_i960_ext = +{ + /* Note that the bits from 0 to 15 are unused. */ + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_i960_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_ext = +{ + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_m88110_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_harris_ext = +{ + /* Harris uses raw format 128 bytes long, but the number is just an ieee + double, and the last 64 bits are wasted. */ + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, + floatformat_intbit_no, + "floatformat_m88110_ext_harris", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_big = +{ + /* Bits 1 to 16 are unused. */ + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_big", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_littlebyte_bigword = +{ + /* Bits 1 to 16 are unused. */ + floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_littlebyte_bigword", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_big = +{ + floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_little = +{ + floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_big = +{ + floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_little = +{ + floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_little", + floatformat_always_valid +}; + +/* Extract a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (const unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len) +{ + unsigned long result; + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + result = *(data + cur_byte) >> (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + /* This is the last byte; zero out the bits which are not part of + this field. */ + result |= + (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) + << cur_bitshift; + else + result |= *(data + cur_byte) << cur_bitshift; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } + return result; +} + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +floatformat_to_double (const struct floatformat *fmt, + const char *from, double *to) +{ + const unsigned char *ufrom = (const unsigned char *)from; + double dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + int special_exponent; /* It's a NaN, denorm or zero */ + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + + /* If the exponent indicates a NaN, we don't have information to + decide what to do. So we handle it like IEEE, except that we + don't try to preserve the type of NaN. FIXME. */ + if ((unsigned long) exponent == fmt->exp_nan) + { + int nan; + + mant_off = fmt->man_start; + mant_bits_left = fmt->man_len; + nan = 0; + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits) != 0) + { + /* This is a NaN. */ + nan = 1; + break; + } + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* On certain systems (such as GNU/Linux), the use of the + INFINITY macro below may generate a warning that can not be + silenced due to a bug in GCC (PR preprocessor/11931). The + preprocessor fails to recognise the __extension__ keyword in + conjunction with the GNU/C99 extension for hexadecimal + floating point constants and will issue a warning when + compiling with -pedantic. */ + if (nan) + dto = NAN; + else + dto = INFINITY; + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + + *to = dto; + + return; + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + + special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; + + /* Don't bias zero's, denorms or NaNs. */ + if (!special_exponent) + exponent -= fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + + /* If this format uses a hidden bit, explicitly add it in now. Otherwise, + increment the exponent by one to account for the integer bit. */ + + if (!special_exponent) + { + if (fmt->intbit == floatformat_intbit_no) + dto = ldexp (1.0, exponent); + else + exponent++; + } + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + /* Handle denormalized numbers. FIXME: What should we do for + non-IEEE formats? */ + if (exponent == 0 && mant != 0) + dto += ldexp ((double)mant, + (- fmt->exp_bias + - mant_bits + - (mant_off - fmt->man_start) + + 1)); + else + dto += ldexp ((double)mant, exponent - mant_bits); + if (exponent != 0) + exponent -= mant_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + *to = dto; +} + +static void put_field (unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int, + unsigned long); + +/* Set a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len, + unsigned long stuff_to_put) +{ + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + *(data + cur_byte) &= + ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); + *(data + cur_byte) |= + (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + { + /* This is the last byte. */ + *(data + cur_byte) &= + ~((1 << (len - cur_bitshift)) - 1); + *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); + } + else + *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) + & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_double (const struct floatformat *fmt, + const double *from, char *to) +{ + double dfrom; + int exponent; + double mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *)to; + + dfrom = *from; + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); + dfrom = -dfrom; + } + + if (dfrom == 0) + { + /* 0.0. */ + return; + } + + if (dfrom != dfrom) + { + /* NaN. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + /* Be sure it's not infinity, but NaN value is irrelevant. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, + 32, 1); + return; + } + + if (dfrom + dfrom == dfrom) + { + /* This can only happen for an infinite value (or zero, which we + already handled above). */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + return; + } + + mant = frexp (dfrom, &exponent); + if (exponent + fmt->exp_bias - 1 > 0) + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, exponent + fmt->exp_bias - 1); + else + { + /* Handle a denormalized number. FIXME: What should we do for + non-IEEE formats? */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + mant = ldexp (mant, exponent + fmt->exp_bias - 1); + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = (unsigned long)mant; + mant -= mant_long; + + /* If the integer bit is implicit, and we are not creating a + denormalized number, then we need to discard it. */ + if ((unsigned int) mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no + && exponent + fmt->exp_bias - 1 > 0) + { + mant_long &= 0x7fffffff; + mant_bits -= 1; + } + else if (mant_bits < 32) + { + /* The bits we want are in the most significant MANT_BITS bits of + mant_long. Move them to the least significant. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } +} + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +int +floatformat_is_valid (const struct floatformat *fmt, const char *from) +{ + return fmt->is_valid (fmt, from); +} + + +#ifdef IEEE_DEBUG + +/* This is to be run on a host which uses IEEE floating point. */ + +void +ieee_test (double n) +{ + double result; + + floatformat_to_double (&floatformat_ieee_double_little, (char *) &n, + &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(to): %.20g -> %.20g\n", n, result); + + floatformat_from_double (&floatformat_ieee_double_little, &n, + (char *) &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(from): %.20g -> %.20g\n", n, result); + +#if 0 + { + char exten[16]; + + floatformat_from_double (&floatformat_m68881_ext, &n, exten); + floatformat_to_double (&floatformat_m68881_ext, exten, &result); + if (n != result) + printf ("Differ(to+from): %.20g -> %.20g\n", n, result); + } +#endif + +#if IEEE_DEBUG > 1 + /* This is to be run on a host which uses 68881 format. */ + { + long double ex = *(long double *)exten; + if (ex != n) + printf ("Differ(from vs. extended): %.20g\n", n); + } +#endif +} + +int +main (void) +{ + ieee_test (0.0); + ieee_test (0.5); + ieee_test (256.0); + ieee_test (0.12345); + ieee_test (234235.78907234); + ieee_test (-512.0); + ieee_test (-0.004321); + ieee_test (1.2E-70); + ieee_test (1.2E-316); + ieee_test (4.9406564584124654E-324); + ieee_test (- 4.9406564584124654E-324); + ieee_test (- 0.0); + ieee_test (- INFINITY); + ieee_test (- NAN); + ieee_test (INFINITY); + ieee_test (NAN); + return 0; +} +#endif +/* **** End of floatformat.c */ diff --git a/qemu/qemu-git/.svn/text-base/m68k.ld.svn-base b/qemu/qemu-git/.svn/text-base/m68k.ld.svn-base new file mode 100644 index 0000000..0e3d9de --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/m68k.ld.svn-base @@ -0,0 +1,175 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", + "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x4e754e75 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x4e754e75 + .fini : + { + KEEP (*(.fini)) + } =0x4e754e75 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x2000) + (. & (0x2000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/qemu/qemu-git/.svn/text-base/microblaze-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/microblaze-dis.c.svn-base new file mode 100644 index 0000000..aa68f16 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/microblaze-dis.c.svn-base @@ -0,0 +1,1102 @@ +/* Disassemble Xilinx microblaze instructions. + Copyright (C) 1993, 1999, 2000 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#include +#define STATIC_TABLE +#define DEFINE_TABLE + +#define TRUE 1 +#define FALSE 0 + +#ifndef MICROBLAZE_OPC +#define MICROBLAZE_OPC +/* Assembler instructions for Xilinx's microblaze processor + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#ifndef MICROBLAZE_OPCM +#define MICROBLAZE_OPCM + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + * $Header: + */ + +enum microblaze_instr { + add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu, + addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul, mulh, mulhu, mulhsu, + idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput, + ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor, + andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, wdcclear, wdcflush, mts, mfs, br, brd, + brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt, + bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni, + imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid, + brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti, + bgtid, bgei, bgeid, lbu, lhu, lw, lwx, sb, sh, sw, swx, lbui, lhui, lwi, + sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv, + fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, flt, fint, fsqrt, + tget, tcget, tnget, tncget, tput, tcput, tnput, tncput, + eget, ecget, neget, necget, eput, ecput, neput, necput, + teget, tecget, tneget, tnecget, teput, tecput, tneput, tnecput, + aget, caget, naget, ncaget, aput, caput, naput, ncaput, + taget, tcaget, tnaget, tncaget, taput, tcaput, tnaput, tncaput, + eaget, ecaget, neaget, necaget, eaput, ecaput, neaput, necaput, + teaget, tecaget, tneaget, tnecaget, teaput, tecaput, tneaput, tnecaput, + getd, tgetd, cgetd, tcgetd, ngetd, tngetd, ncgetd, tncgetd, + putd, tputd, cputd, tcputd, nputd, tnputd, ncputd, tncputd, + egetd, tegetd, ecgetd, tecgetd, negetd, tnegetd, necgetd, tnecgetd, + eputd, teputd, ecputd, tecputd, neputd, tneputd, necputd, tnecputd, + agetd, tagetd, cagetd, tcagetd, nagetd, tnagetd, ncagetd, tncagetd, + aputd, taputd, caputd, tcaputd, naputd, tnaputd, ncaputd, tncaputd, + eagetd, teagetd, ecagetd, tecagetd, neagetd, tneagetd, necagetd, tnecagetd, + eaputd, teaputd, ecaputd, tecaputd, neaputd, tneaputd, necaputd, tnecaputd, + invalid_inst } ; + +enum microblaze_instr_type { + arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst, + return_inst, immediate_inst, special_inst, memory_load_inst, + memory_store_inst, barrel_shift_inst, anyware_inst }; + +#define INST_WORD_SIZE 4 + +/* gen purpose regs go from 0 to 31 */ +/* mask is reg num - max_reg_num, ie reg_num - 32 in this case */ + +#define REG_PC_MASK 0x8000 +#define REG_MSR_MASK 0x8001 +#define REG_EAR_MASK 0x8003 +#define REG_ESR_MASK 0x8005 +#define REG_FSR_MASK 0x8007 +#define REG_BTR_MASK 0x800b +#define REG_EDR_MASK 0x800d +#define REG_PVR_MASK 0xa000 + +#define REG_PID_MASK 0x9000 +#define REG_ZPR_MASK 0x9001 +#define REG_TLBX_MASK 0x9002 +#define REG_TLBLO_MASK 0x9003 +#define REG_TLBHI_MASK 0x9004 +#define REG_TLBSX_MASK 0x9005 + +#define MIN_REGNUM 0 +#define MAX_REGNUM 31 + +#define MIN_PVR_REGNUM 0 +#define MAX_PVR_REGNUM 15 + +#define REG_PC 32 /* PC */ +#define REG_MSR 33 /* machine status reg */ +#define REG_EAR 35 /* Exception reg */ +#define REG_ESR 37 /* Exception reg */ +#define REG_FSR 39 /* FPU Status reg */ +#define REG_BTR 43 /* Branch Target reg */ +#define REG_EDR 45 /* Exception reg */ +#define REG_PVR 40960 /* Program Verification reg */ + +#define REG_PID 36864 /* MMU: Process ID reg */ +#define REG_ZPR 36865 /* MMU: Zone Protect reg */ +#define REG_TLBX 36866 /* MMU: TLB Index reg */ +#define REG_TLBLO 36867 /* MMU: TLB Low reg */ +#define REG_TLBHI 36868 /* MMU: TLB High reg */ +#define REG_TLBSX 36869 /* MMU: TLB Search Index reg */ + +/* alternate names for gen purpose regs */ +#define REG_SP 1 /* stack pointer */ +#define REG_ROSDP 2 /* read-only small data pointer */ +#define REG_RWSDP 13 /* read-write small data pointer */ + +/* Assembler Register - Used in Delay Slot Optimization */ +#define REG_AS 18 +#define REG_ZERO 0 + +#define RD_LOW 21 /* low bit for RD */ +#define RA_LOW 16 /* low bit for RA */ +#define RB_LOW 11 /* low bit for RB */ +#define IMM_LOW 0 /* low bit for immediate */ + +#define RD_MASK 0x03E00000 +#define RA_MASK 0x001F0000 +#define RB_MASK 0x0000F800 +#define IMM_MASK 0x0000FFFF + +// imm mask for barrel shifts +#define IMM5_MASK 0x0000001F + + +// FSL imm mask for get, put instructions +#define RFSL_MASK 0x000000F + +// imm mask for msrset, msrclr instructions +#define IMM15_MASK 0x00007FFF + +#endif /* MICROBLAZE-OPCM */ + +#define INST_TYPE_RD_R1_R2 0 +#define INST_TYPE_RD_R1_IMM 1 +#define INST_TYPE_RD_R1_UNSIGNED_IMM 2 +#define INST_TYPE_RD_R1 3 +#define INST_TYPE_RD_R2 4 +#define INST_TYPE_RD_IMM 5 +#define INST_TYPE_R2 6 +#define INST_TYPE_R1_R2 7 +#define INST_TYPE_R1_IMM 8 +#define INST_TYPE_IMM 9 +#define INST_TYPE_SPECIAL_R1 10 +#define INST_TYPE_RD_SPECIAL 11 +#define INST_TYPE_R1 12 + // new instn type for barrel shift imms +#define INST_TYPE_RD_R1_IMM5 13 +#define INST_TYPE_RD_RFSL 14 +#define INST_TYPE_R1_RFSL 15 + + // new insn type for insn cache +#define INST_TYPE_RD_R1_SPECIAL 16 + +// new insn type for msrclr, msrset insns. +#define INST_TYPE_RD_IMM15 17 + +// new insn type for tuqula rd - addik rd, r0, 42 +#define INST_TYPE_RD 18 + +// new insn type for t*put +#define INST_TYPE_RFSL 19 + +#define INST_TYPE_NONE 25 + + + +#define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/ +#define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/ + +#define IMMVAL_MASK_NON_SPECIAL 0x0000 +#define IMMVAL_MASK_MTS 0x4000 +#define IMMVAL_MASK_MFS 0x0000 + +#define OPCODE_MASK_H 0xFC000000 /* High 6 bits only */ +#define OPCODE_MASK_H1 0xFFE00000 /* High 11 bits */ +#define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16 */ +#define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */ +#define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits */ +#define OPCODE_MASK_H13S 0xFFE0EFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H23S 0xFC1FC000 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */ +#define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */ +#define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */ +#define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits */ +#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */ +#define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22 */ +#define OPCODE_MASK_H32 0xFC00FC00 /* High 6 bits and bit 16-21 */ +#define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits */ +#define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26 */ + +// New Mask for msrset, msrclr insns. +#define OPCODE_MASK_H23N 0xFC1F8000 /* High 6 and bits 11 - 16 */ + +#define DELAY_SLOT 1 +#define NO_DELAY_SLOT 0 + +#define MAX_OPCODES 280 + +struct op_code_struct { + const char *name; + short inst_type; /* registers and immediate values involved */ + short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */ + short delay_slots; /* info about delay slots needed after this instr. */ + short immval_mask; + unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */ + unsigned long opcode_mask; /* which bits define the opcode */ + enum microblaze_instr instr; + enum microblaze_instr_type instr_type; + /* more info about output format here */ +} opcodes[MAX_OPCODES] = + +{ + {"add", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst }, + {"rsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst }, + {"addc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst }, + {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst }, + {"addk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst }, + {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst }, + {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst }, + {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst }, + {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst }, + {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst }, + {"addi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst }, + {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst }, + {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst }, + {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst }, + {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst }, + {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst }, + {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst }, + {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst }, + {"mul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst }, + {"mulh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000001, OPCODE_MASK_H4, mulh, mult_inst }, + {"mulhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000003, OPCODE_MASK_H4, mulhu, mult_inst }, + {"mulhsu",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000002, OPCODE_MASK_H4, mulhsu, mult_inst }, + {"idiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst }, + {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst }, + {"bsll", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst }, + {"bsra", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst }, + {"bsrl", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst }, + {"get", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst }, + {"put", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst }, + {"nget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst }, + {"nput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst }, + {"cget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst }, + {"cput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst }, + {"ncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst }, + {"ncput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst }, + {"muli", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst }, + {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst }, + {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst }, + {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst }, + {"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst }, + {"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst }, + {"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst }, + {"andn", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst }, + {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst }, + {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst }, + {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst }, + {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst }, + {"sra", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst }, + {"src", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst }, + {"srl", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst }, + {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst }, + {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst }, + {"wic", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst }, + {"wdc", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst }, + {"wdc.clear", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000066, OPCODE_MASK_H34B, wdcclear, special_inst }, + {"wdc.flush", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000074, OPCODE_MASK_H34B, wdcflush, special_inst }, + {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst }, + {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst }, + {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst }, + {"brd", INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst }, + {"brld", INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst }, + {"bra", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst }, + {"brad", INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst }, + {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst }, + {"brk", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst }, + {"beq", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst }, + {"beqd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst }, + {"bne", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst }, + {"bned", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst }, + {"blt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst }, + {"bltd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst }, + {"ble", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst }, + {"bled", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst }, + {"bgt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst }, + {"bgtd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst }, + {"bge", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst }, + {"bged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst }, + {"ori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst }, + {"andi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst }, + {"xori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst }, + {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst }, + {"imm", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst }, + {"rtsd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst }, + {"rtid", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst }, + {"rtbd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst }, + {"rted", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst }, + {"bri", INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst }, + {"brid", INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst }, + {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst }, + {"brai", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst }, + {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst }, + {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst }, + {"brki", INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst }, + {"beqi", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst }, + {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst }, + {"bnei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst }, + {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst }, + {"blti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst }, + {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst }, + {"blei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst }, + {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst }, + {"bgti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst }, + {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst }, + {"bgei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst }, + {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst }, + {"lbu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst }, + {"lhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst }, + {"lw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst }, + {"lwx", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000400, OPCODE_MASK_H4, lwx, memory_load_inst }, + {"sb", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst }, + {"sh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst }, + {"sw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst }, + {"swx", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000400, OPCODE_MASK_H4, swx, memory_store_inst }, + {"lbui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst }, + {"lhui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst }, + {"lwi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst }, + {"sbi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst }, + {"shi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst }, + {"swi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst }, + {"nop", INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */ + {"la", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */ + {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */ + {"not", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */ + {"neg", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */ + {"rtb", INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */ + {"sub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */ + {"lmi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst }, + {"smi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst }, + {"msrset",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst }, + {"msrclr",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst }, + {"fadd", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst }, + {"frsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst }, + {"fmul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst }, + {"fdiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst }, + {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst }, + {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst }, + {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst }, + {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst }, + {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst }, + {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst }, + {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst }, + {"flt", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000280, OPCODE_MASK_H4, flt, arithmetic_inst }, + {"fint", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000300, OPCODE_MASK_H4, fint, arithmetic_inst }, + {"fsqrt", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000380, OPCODE_MASK_H4, fsqrt, arithmetic_inst }, + {"tget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001000, OPCODE_MASK_H32, tget, anyware_inst }, + {"tcget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003000, OPCODE_MASK_H32, tcget, anyware_inst }, + {"tnget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005000, OPCODE_MASK_H32, tnget, anyware_inst }, + {"tncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007000, OPCODE_MASK_H32, tncget, anyware_inst }, + {"tput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009000, OPCODE_MASK_H32, tput, anyware_inst }, + {"tcput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B000, OPCODE_MASK_H32, tcput, anyware_inst }, + {"tnput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D000, OPCODE_MASK_H32, tnput, anyware_inst }, + {"tncput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F000, OPCODE_MASK_H32, tncput, anyware_inst }, + + {"eget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000400, OPCODE_MASK_H32, eget, anyware_inst }, + {"ecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002400, OPCODE_MASK_H32, ecget, anyware_inst }, + {"neget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004400, OPCODE_MASK_H32, neget, anyware_inst }, + {"necget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006400, OPCODE_MASK_H32, necget, anyware_inst }, + {"eput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008400, OPCODE_MASK_H32, eput, anyware_inst }, + {"ecput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A400, OPCODE_MASK_H32, ecput, anyware_inst }, + {"neput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C400, OPCODE_MASK_H32, neput, anyware_inst }, + {"necput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E400, OPCODE_MASK_H32, necput, anyware_inst }, + + {"teget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001400, OPCODE_MASK_H32, teget, anyware_inst }, + {"tecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003400, OPCODE_MASK_H32, tecget, anyware_inst }, + {"tneget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005400, OPCODE_MASK_H32, tneget, anyware_inst }, + {"tnecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007400, OPCODE_MASK_H32, tnecget, anyware_inst }, + {"teput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009400, OPCODE_MASK_H32, teput, anyware_inst }, + {"tecput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B400, OPCODE_MASK_H32, tecput, anyware_inst }, + {"tneput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D400, OPCODE_MASK_H32, tneput, anyware_inst }, + {"tnecput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F400, OPCODE_MASK_H32, tnecput, anyware_inst }, + + {"aget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000800, OPCODE_MASK_H32, aget, anyware_inst }, + {"caget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002800, OPCODE_MASK_H32, caget, anyware_inst }, + {"naget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004800, OPCODE_MASK_H32, naget, anyware_inst }, + {"ncaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006800, OPCODE_MASK_H32, ncaget, anyware_inst }, + {"aput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008800, OPCODE_MASK_H32, aput, anyware_inst }, + {"caput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A800, OPCODE_MASK_H32, caput, anyware_inst }, + {"naput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C800, OPCODE_MASK_H32, naput, anyware_inst }, + {"ncaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E800, OPCODE_MASK_H32, ncaput, anyware_inst }, + + {"taget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001800, OPCODE_MASK_H32, taget, anyware_inst }, + {"tcaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003800, OPCODE_MASK_H32, tcaget, anyware_inst }, + {"tnaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005800, OPCODE_MASK_H32, tnaget, anyware_inst }, + {"tncaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007800, OPCODE_MASK_H32, tncaget, anyware_inst }, + {"taput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009800, OPCODE_MASK_H32, taput, anyware_inst }, + {"tcaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B800, OPCODE_MASK_H32, tcaput, anyware_inst }, + {"tnaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D800, OPCODE_MASK_H32, tnaput, anyware_inst }, + {"tncaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F800, OPCODE_MASK_H32, tncaput, anyware_inst }, + + {"eaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000C00, OPCODE_MASK_H32, eget, anyware_inst }, + {"ecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002C00, OPCODE_MASK_H32, ecget, anyware_inst }, + {"neaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004C00, OPCODE_MASK_H32, neget, anyware_inst }, + {"necaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006C00, OPCODE_MASK_H32, necget, anyware_inst }, + {"eaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008C00, OPCODE_MASK_H32, eput, anyware_inst }, + {"ecaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00AC00, OPCODE_MASK_H32, ecput, anyware_inst }, + {"neaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00CC00, OPCODE_MASK_H32, neput, anyware_inst }, + {"necaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00EC00, OPCODE_MASK_H32, necput, anyware_inst }, + + {"teaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001C00, OPCODE_MASK_H32, teaget, anyware_inst }, + {"tecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003C00, OPCODE_MASK_H32, tecaget, anyware_inst }, + {"tneaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005C00, OPCODE_MASK_H32, tneaget, anyware_inst }, + {"tnecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007C00, OPCODE_MASK_H32, tnecaget, anyware_inst }, + {"teaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009C00, OPCODE_MASK_H32, teaput, anyware_inst }, + {"tecaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00BC00, OPCODE_MASK_H32, tecaput, anyware_inst }, + {"tneaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00DC00, OPCODE_MASK_H32, tneaput, anyware_inst }, + {"tnecaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00FC00, OPCODE_MASK_H32, tnecaput, anyware_inst }, + + {"getd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000000, OPCODE_MASK_H34C, getd, anyware_inst }, + {"tgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000080, OPCODE_MASK_H34C, tgetd, anyware_inst }, + {"cgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000100, OPCODE_MASK_H34C, cgetd, anyware_inst }, + {"tcgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000180, OPCODE_MASK_H34C, tcgetd, anyware_inst }, + {"ngetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000200, OPCODE_MASK_H34C, ngetd, anyware_inst }, + {"tngetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000280, OPCODE_MASK_H34C, tngetd, anyware_inst }, + {"ncgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000300, OPCODE_MASK_H34C, ncgetd, anyware_inst }, + {"tncgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000380, OPCODE_MASK_H34C, tncgetd, anyware_inst }, + {"putd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000400, OPCODE_MASK_H34C, putd, anyware_inst }, + {"tputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000480, OPCODE_MASK_H34C, tputd, anyware_inst }, + {"cputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000500, OPCODE_MASK_H34C, cputd, anyware_inst }, + {"tcputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000580, OPCODE_MASK_H34C, tcputd, anyware_inst }, + {"nputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000600, OPCODE_MASK_H34C, nputd, anyware_inst }, + {"tnputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000680, OPCODE_MASK_H34C, tnputd, anyware_inst }, + {"ncputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000700, OPCODE_MASK_H34C, ncputd, anyware_inst }, + {"tncputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000780, OPCODE_MASK_H34C, tncputd, anyware_inst }, + + {"egetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000020, OPCODE_MASK_H34C, egetd, anyware_inst }, + {"tegetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000A0, OPCODE_MASK_H34C, tegetd, anyware_inst }, + {"ecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000120, OPCODE_MASK_H34C, ecgetd, anyware_inst }, + {"tecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001A0, OPCODE_MASK_H34C, tecgetd, anyware_inst }, + {"negetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000220, OPCODE_MASK_H34C, negetd, anyware_inst }, + {"tnegetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002A0, OPCODE_MASK_H34C, tnegetd, anyware_inst }, + {"necgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000320, OPCODE_MASK_H34C, necgetd, anyware_inst }, + {"tnecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003A0, OPCODE_MASK_H34C, tnecgetd, anyware_inst }, + {"eputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000420, OPCODE_MASK_H34C, eputd, anyware_inst }, + {"teputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004A0, OPCODE_MASK_H34C, teputd, anyware_inst }, + {"ecputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000520, OPCODE_MASK_H34C, ecputd, anyware_inst }, + {"tecputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005A0, OPCODE_MASK_H34C, tecputd, anyware_inst }, + {"neputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000620, OPCODE_MASK_H34C, neputd, anyware_inst }, + {"tneputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006A0, OPCODE_MASK_H34C, tneputd, anyware_inst }, + {"necputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000720, OPCODE_MASK_H34C, necputd, anyware_inst }, + {"tnecputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007A0, OPCODE_MASK_H34C, tnecputd, anyware_inst }, + + {"agetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000040, OPCODE_MASK_H34C, agetd, anyware_inst }, + {"tagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000C0, OPCODE_MASK_H34C, tagetd, anyware_inst }, + {"cagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000140, OPCODE_MASK_H34C, cagetd, anyware_inst }, + {"tcagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001C0, OPCODE_MASK_H34C, tcagetd, anyware_inst }, + {"nagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000240, OPCODE_MASK_H34C, nagetd, anyware_inst }, + {"tnagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002C0, OPCODE_MASK_H34C, tnagetd, anyware_inst }, + {"ncagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000340, OPCODE_MASK_H34C, ncagetd, anyware_inst }, + {"tncagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003C0, OPCODE_MASK_H34C, tncagetd, anyware_inst }, + {"aputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000440, OPCODE_MASK_H34C, aputd, anyware_inst }, + {"taputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004C0, OPCODE_MASK_H34C, taputd, anyware_inst }, + {"caputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000540, OPCODE_MASK_H34C, caputd, anyware_inst }, + {"tcaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005C0, OPCODE_MASK_H34C, tcaputd, anyware_inst }, + {"naputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000640, OPCODE_MASK_H34C, naputd, anyware_inst }, + {"tnaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006C0, OPCODE_MASK_H34C, tnaputd, anyware_inst }, + {"ncaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000740, OPCODE_MASK_H34C, ncaputd, anyware_inst }, + {"tncaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007C0, OPCODE_MASK_H34C, tncaputd, anyware_inst }, + + {"eagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000060, OPCODE_MASK_H34C, eagetd, anyware_inst }, + {"teagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000E0, OPCODE_MASK_H34C, teagetd, anyware_inst }, + {"ecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000160, OPCODE_MASK_H34C, ecagetd, anyware_inst }, + {"tecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001E0, OPCODE_MASK_H34C, tecagetd, anyware_inst }, + {"neagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000260, OPCODE_MASK_H34C, neagetd, anyware_inst }, + {"tneagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002E0, OPCODE_MASK_H34C, tneagetd, anyware_inst }, + {"necagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000360, OPCODE_MASK_H34C, necagetd, anyware_inst }, + {"tnecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003E0, OPCODE_MASK_H34C, tnecagetd, anyware_inst }, + {"eaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000460, OPCODE_MASK_H34C, eaputd, anyware_inst }, + {"teaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004E0, OPCODE_MASK_H34C, teaputd, anyware_inst }, + {"ecaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000560, OPCODE_MASK_H34C, ecaputd, anyware_inst }, + {"tecaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005E0, OPCODE_MASK_H34C, tecaputd, anyware_inst }, + {"neaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000660, OPCODE_MASK_H34C, neaputd, anyware_inst }, + {"tneaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006E0, OPCODE_MASK_H34C, tneaputd, anyware_inst }, + {"necaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000760, OPCODE_MASK_H34C, necaputd, anyware_inst }, + {"tnecaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007E0, OPCODE_MASK_H34C, tnecaputd, anyware_inst }, + {"", 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +/* prefix for register names */ +char register_prefix[] = "r"; +char special_register_prefix[] = "spr"; +char fsl_register_prefix[] = "rfsl"; +char pvr_register_prefix[] = "rpvr"; + + +/* #defines for valid immediate range */ +#define MIN_IMM ((int) 0x80000000) +#define MAX_IMM ((int) 0x7fffffff) + +#define MIN_IMM15 ((int) 0x0000) +#define MAX_IMM15 ((int) 0x7fff) + +#endif /* MICROBLAZE_OPC */ + +#include "dis-asm.h" +#include + +#define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW) +#define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW) +#define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW) +#define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW) +#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW) + +/* Local function prototypes. */ + +static char * get_field (long instr, long mask, unsigned short low); +static char * get_field_imm (long instr); +static char * get_field_imm5 (long instr); +static char * get_field_rfsl (long instr); +static char * get_field_imm15 (long instr); +#if 0 +static char * get_field_unsigned_imm (long instr); +#endif +char * get_field_special (long instr, struct op_code_struct * op); +unsigned long read_insn_microblaze (bfd_vma memaddr, + struct disassemble_info *info, + struct op_code_struct **opr); +enum microblaze_instr get_insn_microblaze (long inst, + bfd_boolean *isunsignedimm, + enum microblaze_instr_type *insn_type, + short *delay_slots); +short get_delay_slots_microblaze (long inst); +enum microblaze_instr microblaze_decode_insn (long insn, + int *rd, + int *ra, + int *rb, + int *imm); +unsigned long +microblaze_get_target_address (long inst, + bfd_boolean immfound, + int immval, + long pcval, + long r1val, + long r2val, + bfd_boolean *targetvalid, + bfd_boolean *unconditionalbranch); + +static char * +get_field (long instr, long mask, unsigned short low) +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm5 (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_rfsl (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & RFSL_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm15 (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +#if 0 +static char * +get_field_unsigned_imm (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} +#endif + +/* + char * + get_field_special (instr) + long instr; + { + char tmpstr[25]; + + sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr"); + + return(strdup(tmpstr)); + } +*/ + +char * +get_field_special (long instr, struct op_code_struct * op) +{ + char tmpstr[25]; + char spr[6]; + + switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) { + + case REG_MSR_MASK : + strcpy(spr, "msr"); + break; + case REG_PC_MASK : + strcpy(spr, "pc"); + break; + case REG_EAR_MASK : + strcpy(spr, "ear"); + break; + case REG_ESR_MASK : + strcpy(spr, "esr"); + break; + case REG_FSR_MASK : + strcpy(spr, "fsr"); + break; + case REG_BTR_MASK : + strcpy(spr, "btr"); + break; + case REG_EDR_MASK : + strcpy(spr, "edr"); + break; + case REG_PID_MASK : + strcpy(spr, "pid"); + break; + case REG_ZPR_MASK : + strcpy(spr, "zpr"); + break; + case REG_TLBX_MASK : + strcpy(spr, "tlbx"); + break; + case REG_TLBLO_MASK : + strcpy(spr, "tlblo"); + break; + case REG_TLBHI_MASK : + strcpy(spr, "tlbhi"); + break; + case REG_TLBSX_MASK : + strcpy(spr, "tlbsx"); + break; + default : + { + if ( ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000) == REG_PVR_MASK) { + sprintf(tmpstr, "%spvr%d", register_prefix, (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ^ REG_PVR_MASK); + return(strdup(tmpstr)); + } else { + strcpy(spr, "pc"); + } + } + break; + } + + sprintf(tmpstr, "%s%s", register_prefix, spr); + return(strdup(tmpstr)); +} + +unsigned long +read_insn_microblaze (bfd_vma memaddr, + struct disassemble_info *info, + struct op_code_struct **opr) +{ + unsigned char ibytes[4]; + int status; + struct op_code_struct * op; + unsigned long inst; + + status = info->read_memory_func (memaddr, ibytes, 4, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return 0; + } + + if (info->endian == BFD_ENDIAN_BIG) + inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3]; + else if (info->endian == BFD_ENDIAN_LITTLE) + inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0]; + else + abort (); + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + *opr = op; + return inst; +} + + +int +print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) +{ + fprintf_ftype fprintf = info->fprintf_func; + void * stream = info->stream; + unsigned long inst, prev_inst; + struct op_code_struct * op, *pop; + int immval = 0; + bfd_boolean immfound = FALSE; + static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */ + static int prev_insn_vma = -1; /*init the prev insn vma */ + int curr_insn_vma = info->buffer_vma; + + info->bytes_per_chunk = 4; + + inst = read_insn_microblaze (memaddr, info, &op); + if (inst == 0) { + return -1; + } + + if (prev_insn_vma == curr_insn_vma) { + if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) { + prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop); + if (prev_inst == 0) + return -1; + if (pop->instr == imm) { + immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000; + immfound = TRUE; + } + else { + immval = 0; + immfound = FALSE; + } + } + } + /* make curr insn as prev insn */ + prev_insn_addr = memaddr; + prev_insn_vma = curr_insn_vma; + + if (op->name == 0) { + fprintf (stream, ".short 0x%04x", inst); + } + else + { + fprintf (stream, "%s", op->name); + + switch (op->inst_type) + { + case INST_TYPE_RD_R1_R2: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_R1_IMM: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst)); + if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_RD_R1_IMM5: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst)); + break; + case INST_TYPE_RD_RFSL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_rfsl(inst)); + break; + case INST_TYPE_R1_RFSL: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_rfsl(inst)); + break; + case INST_TYPE_RD_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op)); + break; + case INST_TYPE_SPECIAL_R1: + fprintf(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst)); + break; + case INST_TYPE_RD_R1: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst)); + break; + case INST_TYPE_R1_R2: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_R1_IMM: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst)); + /* The non-pc relative instructions are returns, which shouldn't + have a label printed */ + if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + immval += memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_IMM: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_IMM: + fprintf(stream, "\t%s", get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else if (op->inst_offset_type == INST_PC_OFFSET) { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_R2: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_R2: + fprintf(stream, "\t%s", get_field_r2(inst)); + break; + case INST_TYPE_R1: + fprintf(stream, "\t%s", get_field_r1(inst)); + break; + case INST_TYPE_RD_R1_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_IMM15: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm15(inst)); + break; + /* For tuqula instruction */ + case INST_TYPE_RD: + fprintf(stream, "\t%s", get_field_rd(inst)); + break; + case INST_TYPE_RFSL: + fprintf(stream, "\t%s", get_field_rfsl(inst)); + break; + default: + /* if the disassembler lags the instruction set */ + fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst); + break; + } + } + + /* Say how many bytes we consumed? */ + return 4; +} + +enum microblaze_instr +get_insn_microblaze (long inst, + bfd_boolean *isunsignedimm, + enum microblaze_instr_type *insn_type, + short *delay_slots) +{ + struct op_code_struct * op; + *isunsignedimm = FALSE; + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) + return invalid_inst; + else { + *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM); + *insn_type = op->instr_type; + *delay_slots = op->delay_slots; + return op->instr; + } +} + +short +get_delay_slots_microblaze (long inst) +{ + bfd_boolean isunsignedimm; + enum microblaze_instr_type insn_type; + enum microblaze_instr op; + short delay_slots; + + op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots); + if (op == invalid_inst) + return 0; + else + return delay_slots; +} + +enum microblaze_instr +microblaze_decode_insn (long insn, + int *rd, + int *ra, + int *rb, + int *imm) +{ + enum microblaze_instr op; + bfd_boolean t1; + enum microblaze_instr_type t2; + short t3; + + op = get_insn_microblaze(insn, &t1, &t2, &t3); + *rd = (insn & RD_MASK) >> RD_LOW; + *ra = (insn & RA_MASK) >> RA_LOW; + *rb = (insn & RB_MASK) >> RB_LOW; + t3 = (insn & IMM_MASK) >> IMM_LOW; + *imm = (int) t3; + return (op); +} + +unsigned long +microblaze_get_target_address (long inst, + bfd_boolean immfound, + int immval, + long pcval, + long r1val, + long r2val, + bfd_boolean *targetvalid, + bfd_boolean *unconditionalbranch) +{ + struct op_code_struct * op; + long targetaddr = 0; + + *unconditionalbranch = FALSE; + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) { + *targetvalid = FALSE; + } else if (op->instr_type == branch_inst) { + switch (op->inst_type) { + case INST_TYPE_R2: + *unconditionalbranch = TRUE; + /* fallthru */ + case INST_TYPE_RD_R2: + case INST_TYPE_R1_R2: + targetaddr = r2val; + *targetvalid = TRUE; + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + break; + case INST_TYPE_IMM: + *unconditionalbranch = TRUE; + /* fallthru */ + case INST_TYPE_RD_IMM: + case INST_TYPE_R1_IMM: + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + *targetvalid = TRUE; + break; + default: + *targetvalid = FALSE; + break; + } + } else if (op->instr_type == return_inst) { + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + targetaddr += r1val; + *targetvalid = TRUE; + } else { + *targetvalid = FALSE; + } + return targetaddr; +} diff --git a/qemu/qemu-git/.svn/text-base/mips-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/mips-dis.c.svn-base new file mode 100644 index 0000000..169169c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/mips-dis.c.svn-base @@ -0,0 +1,4842 @@ +/* Print mips instructions for GDB, the GNU debugger, or for objdump. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). + +This file is part of GDB, GAS, and the GNU binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#include "dis-asm.h" + +/* mips.h. Mips opcode list for GDB, the GNU debugger. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Ralph Campbell and OSF + Commented and modified by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). An optional two-operand form of break/sdbbp + allows the lower ten bits to be set too, and MIPS32 and later + architectures allow 20 bits to be set with a signal operand + (using CODE20). + + The syscall instruction uses CODE20. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_CODE2 0x3ff +#define OP_SH_CODE2 6 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */ +#define OP_SH_CODE20 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 +#define OP_SH_LOCC 8 /* FP condition code. */ +#define OP_SH_HICC 18 /* FP condition code. */ +#define OP_MASK_CC 0x7 +#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */ +#define OP_MASK_COP1NORM 0x1 /* a single bit. */ +#define OP_SH_COP1SPEC 21 /* COP1 encodings. */ +#define OP_MASK_COP1SPEC 0xf +#define OP_MASK_COP1SCLR 0x4 +#define OP_MASK_COP1CMP 0x3 +#define OP_SH_COP1CMP 4 +#define OP_SH_FORMAT 21 /* FP short format field. */ +#define OP_MASK_FORMAT 0x7 +#define OP_SH_TRUE 16 +#define OP_MASK_TRUE 0x1 +#define OP_SH_GE 17 +#define OP_MASK_GE 0x01 +#define OP_SH_UNSIGNED 16 +#define OP_MASK_UNSIGNED 0x1 +#define OP_SH_HINT 16 +#define OP_MASK_HINT 0x1f +#define OP_SH_MMI 0 /* Multimedia (parallel) op. */ +#define OP_MASK_MMI 0x3f +#define OP_SH_MMISUB 6 +#define OP_MASK_MMISUB 0x1f +#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */ +#define OP_SH_PERFREG 1 +#define OP_SH_SEL 0 /* Coprocessor select field. */ +#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */ +#define OP_SH_CODE19 6 /* 19 bit wait code. */ +#define OP_MASK_CODE19 0x7ffff +#define OP_SH_ALN 21 +#define OP_MASK_ALN 0x7 +#define OP_SH_VSEL 21 +#define OP_MASK_VSEL 0x1f +#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits, + but 0x8-0xf don't select bytes. */ +#define OP_SH_VECBYTE 22 +#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */ +#define OP_SH_VECALIGN 21 +#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */ +#define OP_SH_INSMSB 11 +#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */ +#define OP_SH_EXTMSBD 11 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* MIPS DSP ASE */ +#define OP_SH_DSPACC 11 +#define OP_MASK_DSPACC 0x3 +#define OP_SH_DSPACC_S 21 +#define OP_MASK_DSPACC_S 0x3 +#define OP_SH_DSPSFT 20 +#define OP_MASK_DSPSFT 0x3f +#define OP_SH_DSPSFT_7 19 +#define OP_MASK_DSPSFT_7 0x7f +#define OP_SH_SA3 21 +#define OP_MASK_SA3 0x7 +#define OP_SH_SA4 21 +#define OP_MASK_SA4 0xf +#define OP_SH_IMM8 16 +#define OP_MASK_IMM8 0xff +#define OP_SH_IMM10 16 +#define OP_MASK_IMM10 0x3ff +#define OP_SH_WRDSP 11 +#define OP_MASK_WRDSP 0x3f +#define OP_SH_RDDSP 16 +#define OP_MASK_RDDSP 0x3f +#define OP_SH_BP 11 +#define OP_MASK_BP 0x3 + +/* MIPS MT ASE */ +#define OP_SH_MT_U 5 +#define OP_MASK_MT_U 0x1 +#define OP_SH_MT_H 4 +#define OP_MASK_MT_H 0x1 +#define OP_SH_MTACC_T 18 +#define OP_MASK_MTACC_T 0x3 +#define OP_SH_MTACC_D 13 +#define OP_MASK_MTACC_D 0x3 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* Values in the 'VSEL' field. */ +#define MDMX_FMTSEL_IMM_QH 0x1d +#define MDMX_FMTSEL_IMM_OB 0x1e +#define MDMX_FMTSEL_VEC_QH 0x15 +#define MDMX_FMTSEL_VEC_OB 0x16 + +/* UDI */ +#define OP_SH_UDI1 6 +#define OP_MASK_UDI1 0x1f +#define OP_SH_UDI2 6 +#define OP_MASK_UDI2 0x3ff +#define OP_SH_UDI3 6 +#define OP_MASK_UDI3 0x7fff +#define OP_SH_UDI4 6 +#define OP_MASK_UDI4 0xfffff +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is 0. */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned long pinfo2; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned long membership; +}; + +/* These are the characters which may appear in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + Also used for immediate operands in vr5400 vector insns. + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "q" 10 bit extra breakpoint code (OP_*_CODE2) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "U" 5 bit same destination register in both OP_*_RD and OP_*_RT + (used by clo and clz) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall/breakpoint function code (OP_*_CODE20) + "J" 19 bit wait function code (OP_*_CODE19) + "x" accept and ignore register name + "z" must be zero register + "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) + "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes + LSB (OP_*_SHAMT). + Enforces: 0 <= pos < 32. + "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + (Also used by "dext" w/ different limits, but limits for + that are checked by the M_DEXT macro.) + "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT). + Enforces: 32 <= pos < 64. + "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL) + "P" 5 bit performance-monitor register (OP_*_PERFREG) + "e" 5 bit vector register byte specifier (OP_*_VECBYTE) + "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN) + see also "k" above + "+D" Combined destination register ("G") and sel ("H") for CP0 ops, + for pretty-printing in disassembly only. + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate (value placed in imm_expr). + "+I" 32 bit immediate (value placed in imm2_expr). + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 + + MDMX instruction operands (note that while these use the FP register + fields, they accept both $fN and $vN names for the registers): + "O" MDMX alignment offset (OP_*_ALN) + "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) + "X" MDMX destination register (OP_*_FD) + "Y" MDMX source register (OP_*_FS) + "Z" MDMX source register (OP_*_FT) + + DSP ASE usage: + "2" 2 bit unsigned immediate for byte align (OP_*_BP) + "3" 3 bit unsigned immediate (OP_*_SA3) + "4" 4 bit unsigned immediate (OP_*_SA4) + "5" 8 bit unsigned immediate (OP_*_IMM8) + "6" 5 bit unsigned immediate (OP_*_RS) + "7" 2 bit dsp accumulator register (OP_*_DSPACC) + "8" 6 bit unsigned immediate (OP_*_WRDSP) + "9" 2 bit dsp accumulator register (OP_*_DSPACC_S) + "0" 6 bit signed immediate (OP_*_DSPSFT) + ":" 7 bit signed immediate (OP_*_DSPSFT_7) + "'" 6 bit unsigned immediate (OP_*_RDDSP) + "@" 10 bit signed immediate (OP_*_IMM10) + + MT ASE usage: + "!" 1 bit usermode flag (OP_*_MT_U) + "$" 1 bit load high flag (OP_*_MT_H) + "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T) + "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D) + "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD) + "+t" 5 bit coprocessor 0 destination register (OP_*_RT) + "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only + + UDI immediates: + "+1" UDI immediate bits 6-10 + "+2" UDI immediate bits 6-15 + "+3" UDI immediate bits 6-20 + "+4" UDI immediate bits 6-25 + + Other: + "()" parens surrounding optional value + "," separates operands + "[]" brackets around index for vector-op scalar operand specifier (vr5400) + "+" Start of extension sequence. + + Characters used so far, for quick reference when adding more: + "234567890" + "%[]<>(),+:'@!$*&" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklopqrstuvwxz" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "1234" + "ABCDEFGHIT" + "t" +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* Instruction uses single precision floating point. */ +#define FP_S 0x10000000 +/* Instruction uses double precision floating point. */ +#define FP_D 0x20000000 +/* Instruction is part of the tx39's integer multiply family. */ +#define INSN_MULT 0x40000000 +/* Instruction synchronize shared memory. */ +#define INSN_SYNC 0x80000000 + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Instruction reads MDMX accumulator. */ +#define INSN2_READ_MDMX_ACC 0x00000002 +/* Instruction writes MDMX accumulator. */ +#define INSN2_WRITE_MDMX_ACC 0x00000004 + +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. ISAs, as defined below, are logical + ORs of these bits, indicating that they support the instructions + defined at the given level. */ + +#define INSN_ISA_MASK 0x00000fff +#define INSN_ISA1 0x00000001 +#define INSN_ISA2 0x00000002 +#define INSN_ISA3 0x00000004 +#define INSN_ISA4 0x00000008 +#define INSN_ISA5 0x00000010 +#define INSN_ISA32 0x00000020 +#define INSN_ISA64 0x00000040 +#define INSN_ISA32R2 0x00000080 +#define INSN_ISA64R2 0x00000100 + +/* Masks used for MIPS-defined ASEs. */ +#define INSN_ASE_MASK 0x0000f000 + +/* DSP ASE */ +#define INSN_DSP 0x00001000 +#define INSN_DSP64 0x00002000 +/* MIPS 16 ASE */ +#define INSN_MIPS16 0x00004000 +/* MIPS-3D ASE */ +#define INSN_MIPS3D 0x00008000 + +/* Chip specific instructions. These are bitmasks. */ + +/* MIPS R4650 instruction. */ +#define INSN_4650 0x00010000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x00020000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x00040000 +/* Toshiba R3900 instruction. */ +#define INSN_3900 0x00080000 +/* MIPS R10000 instruction. */ +#define INSN_10000 0x00100000 +/* Broadcom SB-1 instruction. */ +#define INSN_SB1 0x00200000 +/* NEC VR4111/VR4181 instruction. */ +#define INSN_4111 0x00400000 +/* NEC VR4120 instruction. */ +#define INSN_4120 0x00800000 +/* NEC VR5400 instruction. */ +#define INSN_5400 0x01000000 +/* NEC VR5500 instruction. */ +#define INSN_5500 0x02000000 + +/* MDMX ASE */ +#define INSN_MDMX 0x04000000 +/* MT ASE */ +#define INSN_MT 0x08000000 +/* SmartMIPS ASE */ +#define INSN_SMARTMIPS 0x10000000 +/* DSP R2 ASE */ +#define INSN_DSPR2 0x20000000 + +/* MIPS ISA defines, use instead of hardcoding ISA level. */ + +#define ISA_UNKNOWN 0 /* Gas internal use. */ +#define ISA_MIPS1 (INSN_ISA1) +#define ISA_MIPS2 (ISA_MIPS1 | INSN_ISA2) +#define ISA_MIPS3 (ISA_MIPS2 | INSN_ISA3) +#define ISA_MIPS4 (ISA_MIPS3 | INSN_ISA4) +#define ISA_MIPS5 (ISA_MIPS4 | INSN_ISA5) + +#define ISA_MIPS32 (ISA_MIPS2 | INSN_ISA32) +#define ISA_MIPS64 (ISA_MIPS5 | INSN_ISA32 | INSN_ISA64) + +#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2) +#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2) + + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ +#define CPU_R3000 3000 +#define CPU_R3900 3900 +#define CPU_R4000 4000 +#define CPU_R4010 4010 +#define CPU_VR4100 4100 +#define CPU_R4111 4111 +#define CPU_VR4120 4120 +#define CPU_R4300 4300 +#define CPU_R4400 4400 +#define CPU_R4600 4600 +#define CPU_R4650 4650 +#define CPU_R5000 5000 +#define CPU_VR5400 5400 +#define CPU_VR5500 5500 +#define CPU_R6000 6000 +#define CPU_RM7000 7000 +#define CPU_R8000 8000 +#define CPU_R10000 10000 +#define CPU_R12000 12000 +#define CPU_MIPS16 16 +#define CPU_MIPS32 32 +#define CPU_MIPS32R2 33 +#define CPU_MIPS5 5 +#define CPU_MIPS64 64 +#define CPU_MIPS64R2 65 +#define CPU_SB1 12310201 /* octal 'SB', 01. */ + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. */ + +#if 0 +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (((insn)->membership & isa) != 0 \ + || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ + || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ + || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ + || ((cpu == CPU_R10000 || cpu == CPU_R12000) \ + && ((insn)->membership & INSN_10000) != 0) \ + || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \ + || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \ + || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \ + || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ + || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ + || 0) /* Please keep this term for easier source merging. */ +#else +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (1 != 0) +#endif + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means address + _AB appended means address with base register + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BALIGN, + M_BEQ, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE, + M_BNE_I, + M_BNEL_I, + M_CACHE_AB, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DEXT, + M_DINS, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLCA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_DSUBU_I_2, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LCA_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MOVE, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_DROR, + M_ROR, + M_DROR_I, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_SUBU_I_2, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I, + M_COP0, + M_COP1, + M_COP2, + M_COP3, + M_NUM_MACROS +}; + + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +extern const struct mips_opcode mips_builtin_opcodes[]; +extern const int bfd_mips_num_builtin_opcodes; +extern struct mips_opcode *mips_opcodes; +extern int bfd_mips_num_opcodes; +#define NUMOPCODES bfd_mips_num_opcodes + + +/* The rest of this file adds definitions for the mips16 TinyRISC + processor. */ + +/* These are the bitmasks and shift counts used for the different + fields in the instruction formats. Other than OP, no masks are + provided for the fixed portions of an instruction, since they are + not needed. + + The I format uses IMM11. + + The RI format uses RX and IMM8. + + The RR format uses RX, and RY. + + The RRI format uses RX, RY, and IMM5. + + The RRR format uses RX, RY, and RZ. + + The RRI_A format uses RX, RY, and IMM4. + + The SHIFT format uses RX, RY, and SHAMT. + + The I8 format uses IMM8. + + The I8_MOVR32 format uses RY and REGR32. + + The IR_MOV32R format uses REG32R and MOV32Z. + + The I64 format uses IMM8. + + The RI64 format uses RY and IMM5. + */ + +#define MIPS16OP_MASK_OP 0x1f +#define MIPS16OP_SH_OP 11 +#define MIPS16OP_MASK_IMM11 0x7ff +#define MIPS16OP_SH_IMM11 0 +#define MIPS16OP_MASK_RX 0x7 +#define MIPS16OP_SH_RX 8 +#define MIPS16OP_MASK_IMM8 0xff +#define MIPS16OP_SH_IMM8 0 +#define MIPS16OP_MASK_RY 0x7 +#define MIPS16OP_SH_RY 5 +#define MIPS16OP_MASK_IMM5 0x1f +#define MIPS16OP_SH_IMM5 0 +#define MIPS16OP_MASK_RZ 0x7 +#define MIPS16OP_SH_RZ 2 +#define MIPS16OP_MASK_IMM4 0xf +#define MIPS16OP_SH_IMM4 0 +#define MIPS16OP_MASK_REGR32 0x1f +#define MIPS16OP_SH_REGR32 0 +#define MIPS16OP_MASK_REG32R 0x1f +#define MIPS16OP_SH_REG32R 3 +#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18)) +#define MIPS16OP_MASK_MOVE32Z 0x7 +#define MIPS16OP_SH_MOVE32Z 0 +#define MIPS16OP_MASK_IMM6 0x3f +#define MIPS16OP_SH_IMM6 5 + +/* These are the characters which may appears in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + "y" 3 bit register (MIPS16OP_*_RY) + "x" 3 bit register (MIPS16OP_*_RX) + "z" 3 bit register (MIPS16OP_*_RZ) + "Z" 3 bit register (MIPS16OP_*_MOVE32Z) + "v" 3 bit same register as source and destination (MIPS16OP_*_RX) + "w" 3 bit same register as source and destination (MIPS16OP_*_RY) + "0" zero register ($0) + "S" stack pointer ($sp or $29) + "P" program counter + "R" return address register ($ra or $31) + "X" 5 bit MIPS register (MIPS16OP_*_REGR32) + "Y" 5 bit MIPS register (MIPS16OP_*_REG32R) + "6" 6 bit unsigned break code (MIPS16OP_*_IMM6) + "a" 26 bit jump address + "e" 11 bit extension value + "l" register list for entry instruction + "L" register list for exit instruction + + The remaining codes may be extended. Except as otherwise noted, + the full extended operand is a 16 bit signed value. + "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned) + ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned) + "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned) + "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned) + "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed) + "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5) + "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5) + "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5) + "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5) + "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5) + "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) + "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8) + "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8) + "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned) + "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8) + "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8) + "p" 8 bit conditional branch address (MIPS16OP_*_IMM8) + "q" 11 bit branch address (MIPS16OP_*_IMM11) + "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8) + "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5) + "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) + */ + +/* Save/restore encoding for the args field when all 4 registers are + either saved as arguments or saved/restored as statics. */ +#define MIPS16_ALL_ARGS 0xe +#define MIPS16_ALL_STATICS 0xb + +/* For the mips16, we use the same opcode table format and a few of + the same flags. However, most of the flags are different. */ + +/* Modifies the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_WRITE_X 0x00000001 +/* Modifies the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_WRITE_Y 0x00000002 +/* Modifies the register in MIPS16OP_*_RZ. */ +#define MIPS16_INSN_WRITE_Z 0x00000004 +/* Modifies the T ($24) register. */ +#define MIPS16_INSN_WRITE_T 0x00000008 +/* Modifies the SP ($29) register. */ +#define MIPS16_INSN_WRITE_SP 0x00000010 +/* Modifies the RA ($31) register. */ +#define MIPS16_INSN_WRITE_31 0x00000020 +/* Modifies the general purpose register in MIPS16OP_*_REG32R. */ +#define MIPS16_INSN_WRITE_GPR_Y 0x00000040 +/* Reads the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_READ_X 0x00000080 +/* Reads the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_READ_Y 0x00000100 +/* Reads the register in MIPS16OP_*_MOVE32Z. */ +#define MIPS16_INSN_READ_Z 0x00000200 +/* Reads the T ($24) register. */ +#define MIPS16_INSN_READ_T 0x00000400 +/* Reads the SP ($29) register. */ +#define MIPS16_INSN_READ_SP 0x00000800 +/* Reads the RA ($31) register. */ +#define MIPS16_INSN_READ_31 0x00001000 +/* Reads the program counter. */ +#define MIPS16_INSN_READ_PC 0x00002000 +/* Reads the general purpose register in MIPS16OP_*_REGR32. */ +#define MIPS16_INSN_READ_GPR_X 0x00004000 +/* Is a branch insn. */ +#define MIPS16_INSN_BRANCH 0x00010000 + +/* The following flags have the same value for the mips16 opcode + table: + INSN_UNCOND_BRANCH_DELAY + INSN_COND_BRANCH_DELAY + INSN_COND_BRANCH_LIKELY (never used) + INSN_READ_HI + INSN_READ_LO + INSN_WRITE_HI + INSN_WRITE_LO + INSN_TRAP + INSN_ISA3 + */ + +extern const struct mips_opcode mips16_opcodes[]; +extern const int bfd_mips16_num_opcodes; + +/* Short hand so the lines aren't too long. */ + +#define LDD INSN_LOAD_MEMORY_DELAY +#define LCD INSN_LOAD_COPROC_DELAY +#define UBD INSN_UNCOND_BRANCH_DELAY +#define CBD INSN_COND_BRANCH_DELAY +#define COD INSN_COPROC_MOVE_DELAY +#define CLD INSN_COPROC_MEMORY_DELAY +#define CBL INSN_COND_BRANCH_LIKELY +#define TRAP INSN_TRAP +#define SM INSN_STORE_MEMORY + +#define WR_d INSN_WRITE_GPR_D +#define WR_t INSN_WRITE_GPR_T +#define WR_31 INSN_WRITE_GPR_31 +#define WR_D INSN_WRITE_FPR_D +#define WR_T INSN_WRITE_FPR_T +#define WR_S INSN_WRITE_FPR_S +#define RD_s INSN_READ_GPR_S +#define RD_b INSN_READ_GPR_S +#define RD_t INSN_READ_GPR_T +#define RD_S INSN_READ_FPR_S +#define RD_T INSN_READ_FPR_T +#define RD_R INSN_READ_FPR_R +#define WR_CC INSN_WRITE_COND_CODE +#define RD_CC INSN_READ_COND_CODE +#define RD_C0 INSN_COP +#define RD_C1 INSN_COP +#define RD_C2 INSN_COP +#define RD_C3 INSN_COP +#define WR_C0 INSN_COP +#define WR_C1 INSN_COP +#define WR_C2 INSN_COP +#define WR_C3 INSN_COP + +#define WR_HI INSN_WRITE_HI +#define RD_HI INSN_READ_HI +#define MOD_HI WR_HI|RD_HI + +#define WR_LO INSN_WRITE_LO +#define RD_LO INSN_READ_LO +#define MOD_LO WR_LO|RD_LO + +#define WR_HILO WR_HI|WR_LO +#define RD_HILO RD_HI|RD_LO +#define MOD_HILO WR_HILO|RD_HILO + +#define IS_M INSN_MULT + +#define WR_MACC INSN2_WRITE_MDMX_ACC +#define RD_MACC INSN2_READ_MDMX_ACC + +#define I1 INSN_ISA1 +#define I2 INSN_ISA2 +#define I3 INSN_ISA3 +#define I4 INSN_ISA4 +#define I5 INSN_ISA5 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define I33 INSN_ISA32R2 +#define I65 INSN_ISA64R2 + +/* MIPS64 MIPS-3D ASE support. */ +#define I16 INSN_MIPS16 + +/* MIPS32 SmartMIPS ASE support. */ +#define SMT INSN_SMARTMIPS + +/* MIPS64 MIPS-3D ASE support. */ +#define M3D INSN_MIPS3D + +/* MIPS64 MDMX ASE support. */ +#define MX INSN_MDMX + +#define P3 INSN_4650 +#define L1 INSN_4010 +#define V1 (INSN_4100 | INSN_4111 | INSN_4120) +#define T3 INSN_3900 +#define M1 INSN_10000 +#define SB1 INSN_SB1 +#define N411 INSN_4111 +#define N412 INSN_4120 +#define N5 (INSN_5400 | INSN_5500) +#define N54 INSN_5400 +#define N55 INSN_5500 + +#define G1 (T3 \ + ) + +#define G2 (T3 \ + ) + +#define G3 (I4 \ + ) + +/* MIPS DSP ASE support. + NOTE: + 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair + of original HI and LO. $ac1, $ac2 and $ac3 are new registers, and have + the same structure as $ac0 (HI + LO). For DSP instructions that write or + read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a + (RD_HILO) attributes, such that HILO dependencies are maintained + conservatively. + + 2. For some mul. instructions that use integer registers as destinations + but destroy HI+LO as side-effect, we add WR_HILO to their attributes. + + 3. MIPS DSP ASE includes a new DSP control register, which has 6 fields + (ccond, outflag, EFI, c, scount, pos). Many DSP instructions read or write + certain fields of the DSP control register. For simplicity, we decide not + to track dependencies of these fields. + However, "bposge32" is a branch instruction that depends on the "pos" + field. In order to make sure that GAS does not reorder DSP instructions + that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP) + attribute to those instructions that write the "pos" field. */ + +#define WR_a WR_HILO /* Write dsp accumulators (reuse WR_HILO) */ +#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */ +#define MOD_a WR_a|RD_a +#define DSP_VOLA INSN_TRAP +#define D32 INSN_DSP +#define D33 INSN_DSPR2 +#define D64 INSN_DSP64 + +/* MIPS MT ASE support. */ +#define MT32 INSN_MT + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Because of the lookup algorithm used, entries with the same opcode + name must be contiguous. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +const struct mips_opcode mips_builtin_opcodes[] = +{ +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, args, match, mask, pinfo, membership */ +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, +{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, INSN2_ALIAS, I32|N55 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, INSN2_ALIAS, I33 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* ori */ +{"li", "t,I", 0, (int) M_LI, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, INSN2_ALIAS, I1 },/* bgezal 0*/ + +{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I1 }, +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, I1 }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, 0, I1 }, +{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, 0, N54 }, +{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX|SB1 }, +{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, 0, I1 }, +{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +/* b is at the top of the table. */ +/* bal is at the top of the table. */ +/* bc0[tf]l? are at the bottom of the table. */ +{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, +/* bc2* are at the bottom of the table. */ +/* bc3* are at the bottom of the table. */ +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, 0, I2|T3 }, +{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, 0, I1 }, +{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1 }, +{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, 0, I2|T3 }, +{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, 0, I2|T3 }, +{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1 }, +{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I1 }, +{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, 0, I2|T3 }, +{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, 0, I1 }, +{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I1 }, +{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, 0, I2|T3 }, +{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, 0, I1 }, +{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I1 }, +{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, 0, I2|T3 }, +{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, 0, I1 }, +{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I1 }, +{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, 0, I2|T3 }, +{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, 0, I2|T3 }, +{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, 0, I1 }, +{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I1 }, +{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, 0, I2|T3 }, +{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, 0, I2|T3 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, 0, I1 }, +{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I1 }, +{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, 0, I2|T3 }, +{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, 0, I2|T3 }, +{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, 0, I1 }, +{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1 }, +{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, 0, I2|T3 }, +{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, 0, I2|T3 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, 0, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, 0, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, 0, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +/* CW4010 instructions which are aliases for the cache instruction. */ +{"flushi", "", 0xbc010000, 0xffffffff, 0, 0, L1 }, +{"flushd", "", 0xbc020000, 0xffffffff, 0, 0, L1 }, +{"flushid", "", 0xbc030000, 0xffffffff, 0, 0, L1 }, +{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, 0, L1 }, +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, 0, I3|I32|T3}, +{"cache", "k,A(b)", 0, (int) M_CACHE_AB, INSN_MACRO, 0, I3|I32|T3}, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +/* cfc2 is at the bottom of the table. */ +/* cfc3 is at the bottom of the table. */ +{"cftc1", "d,E", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc1", "d,T", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc2", "d,E", 0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +/* ctc2 is at the bottom of the table. */ +/* ctc3 is at the bottom of the table. */ +{"cttc1", "t,g", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc1", "t,S", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc2", "t,g", 0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC, 0, MT32 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_S|FP_D, 0, I5|I33 }, +{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, 0, I3 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, 0, I3 }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, 0, I3 }, +{"dbreak", "", 0x7000003f, 0xffffffff, 0, 0, N5 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +/* dctr and dctw are used on the r5000. */ +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, 0, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, 0, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, 0, I32|G2 }, +{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, 0, I65 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* For ddiv, see the comments about div. */ +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, 0, I3 }, +{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, 0, I3 }, +/* For ddivu, see the comments about div. */ +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I3 }, +{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, 0, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, 0, I65 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* The MIPS assembler treats the div opcode with two operands as + though the first operand appeared twice (the first operand is both + a source and a destination). To get the div machine instruction, + you must use an explicit destination of $0. */ +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, 0, I1 }, +{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, 0, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +/* For divu, see the comments about div. */ +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1 }, +{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, 0, I1 }, +{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, 0, I3 }, +{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, 0, I3 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, 0, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, 0, I3 }, /* ori */ +{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, 0, I3 }, +{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, 0, N411 }, +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I3 }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmt", "", 0x41600bc1, 0xffffffff, TRAP, 0, MT32 }, +{"dmt", "t", 0x41600bc1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3 }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +/* dmfc2 is at the bottom of the table. */ +/* dmtc2 is at the bottom of the table. */ +/* dmfc3 is at the bottom of the table. */ +/* dmtc3 is at the bottom of the table. */ +{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, 0, I3 }, +{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, 0, I3 }, +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsubu 0*/ +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, 0, I3 }, +{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, 0, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, 0, I3 }, +{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, 0, I3 }, +{"dret", "", 0x7000003e, 0xffffffff, 0, 0, N5 }, +{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I3 }, +{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I3 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I3 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I3 }, +{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I65 }, +{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I65 }, +{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I65 }, +{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, 0, I3 }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I3 }, +{"dvpe", "", 0x41600001, 0xffffffff, TRAP, 0, MT32 }, +{"dvpe", "t", 0x41600001, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, +{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 }, +{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, +{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"hibernate","", 0x42000023, 0xffffffff, 0, 0, V1 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, +/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with + the same hazard barrier effect. */ +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, 0, I32 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, /* jr */ +/* SVR4 PIC code requires special handling for j, so it must be a + macro. */ +{"j", "a", 0, (int) M_J_A, INSN_MACRO, 0, I1 }, +/* This form of j is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"j", "a", 0x08000000, 0xfc000000, UBD, 0, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, 0, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I1 }, +/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr + with the same hazard barrier effect. */ +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, 0, I32 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I32 }, +/* SVR4 PIC code requires special handling for jal, so it must be a + macro. */ +{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, 0, I1 }, +{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, 0, I1 }, +{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, 0, I1 }, +/* This form of jal is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, 0, I16 }, +{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, 0, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, 0, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, 0, I1 }, +{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, 0, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, 0, I3 }, +{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, 0, I1 }, +{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, 0, I1 }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, /* ldc1 */ +{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, 0, I1 }, +{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, 0, I1 }, +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, 0, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, 0, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, 0, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, 0, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, 0, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, 0, I1 }, +/* li is at the start of the table. */ +{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, 0, I1 }, +{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, 0, I1 }, +{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, 0, I1 }, +{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, 0, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, +{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, 0, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, /* lwc1 */ +{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, 0, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I2 }, /* as lwl */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I2 }, /* as lwr */ +{"fork", "d,s,t", 0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t, 0, MT32 }, +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, LDD|RD_b|RD_t|WR_d, 0, SMT }, +{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"madd", "7,s,t", 0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"maddp", "s,t", 0x70000441, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"maddu", "7,s,t", 0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, N411 }, +{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mftacx", "d", 0x41020021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftacx", "d,*", 0x41020021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftc0", "d,+t", 0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,+T", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,E,H", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc1", "d,T", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc1", "d,E", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc2", "d,E", 0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mftdsp", "d", 0x41100021, 0xffff07ff, TRAP|WR_d, 0, MT32 }, +{"mftgpr", "d,t", 0x41000020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mfthc1", "d,T", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc1", "d,E", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc2", "d,E", 0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mfthi", "d", 0x41010021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mfthi", "d,*", 0x41010021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d", 0x41000021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d,*", 0x41000021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftr", "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d, 0, MT32 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +/* mfc2 is at the bottom of the table. */ +/* mfhc2 is at the bottom of the table. */ +/* mfc3 is at the bottom of the table. */ +{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, 0, N5 }, +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, 0, I1 }, +{"mfhi", "d,9", 0x00000010, 0xff9f07ff, WR_d|RD_HI, 0, D32 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, 0, I1 }, +{"mflo", "d,9", 0x00000012, 0xff9f07ff, WR_d|RD_LO, 0, D32 }, +{"mflhxu", "d", 0x00000052, 0xffff07ff, WR_d|MOD_HILO, 0, SMT }, +{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +/* move is at the top of the table. */ +{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msub", "7,s,t", 0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msubu", "7,s,t", 0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I1 }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +/* mtc2 is at the bottom of the table. */ +/* mthc2 is at the bottom of the table. */ +/* mtc3 is at the bottom of the table. */ +{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, 0, N5 }, +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, 0, I1 }, +{"mthi", "s,7", 0x00000011, 0xfc1fe7ff, RD_s|WR_HI, 0, D32 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, 0, I1 }, +{"mtlo", "s,7", 0x00000013, 0xfc1fe7ff, RD_s|WR_LO, 0, D32 }, +{"mtlhx", "s", 0x00000053, 0xfc1fffff, RD_s|MOD_HILO, 0, SMT }, +{"mttc0", "t,G", 0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,+D", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,G,H", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc1", "t,S", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc1", "t,G", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc2", "t,g", 0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mttacx", "t", 0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttacx", "t,&", 0x41801021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttdsp", "t", 0x41808021, 0xffe0ffff, TRAP|RD_t, 0, MT32 }, +{"mttgpr", "t,d", 0x41800020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mtthc1", "t,S", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc1", "t,G", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc2", "t,g", 0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mtthi", "t", 0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mtthi", "t,&", 0x41800821, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t", 0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t,&", 0x41800021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttr", "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t, 0, MT32 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, I32|P3|N55}, +{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N54 }, +{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, 0, I1 }, +{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, 0, I1 }, +{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, 0, I1 }, +{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, 0, I1 }, +{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"mult", "7,s,t", 0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"multp", "s,t", 0x00000459, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"multu", "7,s,t", 0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +/* nop is at the start of the table. */ +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, 0, I1 }, +{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, 0, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, 0, I1 }, +{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, SB1 }, +{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, + /* pref and prefx are at the start of the table. */ +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"pperm", "s,t", 0x70000481, 0xfc00ffff, MOD_HILO|RD_s|RD_t, 0, SMT }, +{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, 0, N54 }, +{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, 0, N54 }, +{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, 0, N54 }, +{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, 0, I1 }, +{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, 0, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, 0, I1 }, +{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, 0, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, 0, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, 0, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, 0, I1|T3 }, +{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I1 }, +{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I1 }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I1 }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, 0, N5|I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I33|SMT }, +{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I33|SMT }, +{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I33|SMT }, +{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I33|SMT }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, 0, N54 }, +{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, 0, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I2 }, +{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, 0, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I3 }, +{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, 0, I3 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, 0, I1 }, +{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, 0, I1 }, +{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, 0, G2 }, +{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, 0, G2 }, +{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, 0, G2 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, 0, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, 0, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I2 }, +{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, 0, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, 0, I2 }, +{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, 0, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, 0, I1 }, +{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, 0, I1 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, 0, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, 0, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, 0, I1 }, +{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, 0, I1 }, +{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, 0, I1 }, +{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, 0, I1 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, 0, I1 }, +{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, 0, I1 }, +{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, 0, I1 }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, 0, I1 }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, 0, I1 }, +{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, 0, I1 }, +{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, 0, I1 }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, 0, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +/* ssnop is at the start of the table. */ +{"standby", "", 0x42000021, 0xffffffff, 0, 0, V1 }, +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, 0, I1 }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1 }, +{"suspend", "", 0x42000022, 0xffffffff, 0, 0, V1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, 0, I5|I33|N55}, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, 0, I1 }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, 0, I1 }, +{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, 0, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, /* swc1 */ +{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I1 }, +{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, 0, I1 }, +{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, 0, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I2 }, /* as swl */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, 0, I2 }, /* as swr */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S, 0, I4|I33 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2|G1 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, 0, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, 0, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, 0, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* teqi */ +{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, 0, I2 }, +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgei */ +{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, 0, I2 }, +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgeiu */ +{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, 0, I2 }, +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tlti */ +{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, 0, I2 }, +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tltiu */ +{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, 0, I2 }, +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tnei */ +{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, 0, I2 }, +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, 0, I1 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, 0, I1 }, +{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, 0, I3 }, +{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, 0, I3 }, +{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, 0, I1 }, +{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, 0, I1 }, +{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, 0, I1 }, +{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, 0, I1 }, +{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, 0, I1 }, +{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, 0, I1 }, +{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, 0, I3 }, +{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, 0, I3 }, +{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, 0, I1 }, +{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, 0, I1 }, +{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, 0, I1 }, +{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, 0, I1 }, +{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX|SB1 }, +{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, 0, N54 }, +{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX }, +{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, 0, N54 }, +{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, 0, I3|I32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, 0, I32|N55 }, +{"waiti", "", 0x42000020, 0xffffffff, TRAP, 0, L1 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, 0, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, 0, I1 }, +{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"yield", "s", 0x7c000009, 0xfc1fffff, TRAP|RD_s, 0, MT32 }, +{"yield", "d,s", 0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s, 0, MT32 }, + +/* User Defined Instruction. */ +{"udi0", "s,t,d,+1",0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,t,+2", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,+3", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "+4", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,d,+1",0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,+2", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,+3", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "+4", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,d,+1",0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,+2", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,+3", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "+4", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,d,+1",0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,+2", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,+3", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "+4", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,d,+1",0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,+2", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,+3", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "+4", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,d,+1",0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,+2", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,+3", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "+4", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,d,+1",0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,+2", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,+3", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "+4", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,d,+1",0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,+2", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,+3", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "+4", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,d,+1",0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,+2", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,+3", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "+4", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,d,+1",0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,+2", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,+3", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "+4", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,d,+1",0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,+2", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,+3", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "+4", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,d,+1",0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,+2", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,+3", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "+4", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,d,+1",0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,+2", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,+3", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "+4", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,d,+1",0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,+2", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,+3", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "+4", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,d,+1",0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,+2", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,+3", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "+4", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,d,+1",0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,+2", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,+3", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "+4", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, + +/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format + instructions so they are here for the latters to take precedence. */ +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2f", "N,p", 0x49000000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2fl", "N,p", 0x49020000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2t", "N,p", 0x49010000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2tl", "N,p", 0x49030000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I64 }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I32 }, +{"mfhc2", "t,G", 0x48600000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,G,H", 0x48600000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, 0, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I32 }, +{"mthc2", "t,G", 0x48e00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, I33 }, + +/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X + instructions, so they are here for the latters to take precedence. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I3 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I3 }, +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 0, I32 }, +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, 0, I32 }, + +/* No hazard protection on coprocessor instructions--they shouldn't + change the state of the processor and if they do it's up to the + user to put in nops as necessary. These are at the end so that the + disassembler recognizes more specific versions first. */ +{"c0", "C", 0x42000000, 0xfe000000, 0, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, 0, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, 0, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, 0, 0, I1 }, +{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, 0, I1 }, +{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, 0, I1 }, +{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, 0, I1 }, +{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, 0, I1 }, + /* Conflicts with the 4650's "mul" instruction. Nobody's using the + 4010 any more, so move this insn out of the way. If the object + format gave us more info, we could do this right. */ +{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, 0, L1 }, +/* MIPS DSP ASE */ +{"absq_s.ph", "d,t", 0x7c000252, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"absq_s.pw", "d,t", 0x7c000456, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.qh", "d,t", 0x7c000256, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.w", "d,t", 0x7c000452, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"addq.ph", "d,s,t", 0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq.pw", "d,s,t", 0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq.qh", "d,s,t", 0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.ph", "d,s,t", 0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq_s.pw", "d,s,t", 0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.qh", "d,s,t", 0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.w", "d,s,t", 0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addsc", "d,s,t", 0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu.ob", "d,s,t", 0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu.qb", "d,s,t", 0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu_s.ob", "d,s,t", 0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu_s.qb", "d,s,t", 0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addwc", "d,s,t", 0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"bitrev", "d,t", 0x7c0006d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"bposge32", "p", 0x041c0000, 0xffff0000, CBD, 0, D32 }, +{"bposge64", "p", 0x041d0000, 0xffff0000, CBD, 0, D64 }, +{"cmp.eq.ph", "s,t", 0x7c000211, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.eq.pw", "s,t", 0x7c000415, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.eq.qh", "s,t", 0x7c000215, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmp.le.ph", "s,t", 0x7c000291, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.le.pw", "s,t", 0x7c000495, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.le.qh", "s,t", 0x7c000295, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.ph", "s,t", 0x7c000251, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.lt.pw", "s,t", 0x7c000455, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.qh", "s,t", 0x7c000255, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.ob", "s,t", 0x7c000015, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.qb", "s,t", 0x7c000011, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.le.ob", "s,t", 0x7c000095, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.le.qb", "s,t", 0x7c000091, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.lt.ob", "s,t", 0x7c000055, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.lt.qb", "s,t", 0x7c000051, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"dextpdp", "t,7,6", 0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D64 }, +{"dextpdpv", "t,7,s", 0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D64 }, +{"dextp", "t,7,6", 0x7c0000bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextpv", "t,7,s", 0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.l", "t,7,6", 0x7c00043c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.l", "t,7,6", 0x7c00053c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.l", "t,7,6", 0x7c0005bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.w", "t,7,6", 0x7c0001bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.w", "t,7,6", 0x7c00013c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_s.h", "t,7,6", 0x7c0003bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextrv.l", "t,7,s", 0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.l", "t,7,s", 0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.w", "t,7,s", 0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_s.h", "t,7,s", 0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv.w", "t,7,s", 0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.w", "t,7,6", 0x7c00003c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dinsv", "t,s", 0x7c00000d, 0xfc00ffff, WR_t|RD_s, 0, D64 }, +{"dmadd", "7,s,t", 0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmaddu", "7,s,t", 0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsub", "7,s,t", 0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsubu", "7,s,t", 0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmthlip", "s,7", 0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D64 }, +{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obl", "7,s,t", 0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obr", "7,s,t", 0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.qbl", "7,s,t", 0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpau.h.qbr", "7,s,t", 0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obl", "7,s,t", 0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obr", "7,s,t", 0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.qbl", "7,s,t", 0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsu.h.qbr", "7,s,t", 0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dshilo", "7,:", 0x7c0006bc, 0xfc07e7ff, MOD_a, 0, D64 }, +{"dshilov", "7,s", 0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s, 0, D64 }, +{"extpdp", "t,7,6", 0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D32 }, +{"extpdpv", "t,7,s", 0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D32 }, +{"extp", "t,7,6", 0x7c0000b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extpv", "t,7,s", 0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr_rs.w", "t,7,6", 0x7c0001b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_r.w", "t,7,6", 0x7c000138, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_s.h", "t,7,6", 0x7c0003b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extrv_rs.w", "t,7,s", 0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_r.w", "t,7,s", 0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_s.h", "t,7,s", 0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv.w", "t,7,s", 0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr.w", "t,7,6", 0x7c000038, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"insv", "t,s", 0x7c00000c, 0xfc00ffff, WR_t|RD_s, 0, D32 }, +{"lbux", "d,t(b)", 0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"ldx", "d,t(b)", 0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D64 }, +{"lhx", "d,t(b)", 0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"lwx", "d,t(b)", 0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"modsub", "d,s,t", 0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"mthlip", "s,7", 0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D32 }, +{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulq_rs.ph", "d,s,t", 0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"mulq_rs.qh", "d,s,t", 0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"packrl.ph", "d,s,t", 0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"packrl.pw", "d,s,t", 0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ob", "d,s,t", 0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ph", "d,s,t", 0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.pw", "d,s,t", 0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.qb", "d,s,t", 0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.qh", "d,s,t", 0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.w.phl", "d,t", 0x7c000312, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceq.w.phr", "d,t", 0x7c000352, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"raddu.l.ob", "d,s", 0x7c000514, 0xfc1f07ff, WR_d|RD_s, 0, D64 }, +{"raddu.w.qb", "d,s", 0x7c000510, 0xfc1f07ff, WR_d|RD_s, 0, D32 }, +{"rddsp", "d", 0x7fff04b8, 0xffff07ff, WR_d, 0, D32 }, +{"rddsp", "d,'", 0x7c0004b8, 0xffc007ff, WR_d, 0, D32 }, +{"repl.ob", "d,5", 0x7c000096, 0xff0007ff, WR_d, 0, D64 }, +{"repl.ph", "d,@", 0x7c000292, 0xfc0007ff, WR_d, 0, D32 }, +{"repl.pw", "d,@", 0x7c000496, 0xfc0007ff, WR_d, 0, D64 }, +{"repl.qb", "d,5", 0x7c000092, 0xff0007ff, WR_d, 0, D32 }, +{"repl.qh", "d,@", 0x7c000296, 0xfc0007ff, WR_d, 0, D64 }, +{"replv.ob", "d,t", 0x7c0000d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.ph", "d,t", 0x7c0002d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.pw", "d,t", 0x7c0004d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.qb", "d,t", 0x7c0000d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.qh", "d,t", 0x7c0002d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"shilo", "7,0", 0x7c0006b8, 0xfc0fe7ff, MOD_a, 0, D32 }, +{"shilov", "7,s", 0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s, 0, D32 }, +{"shll.ob", "d,t,3", 0x7c000017, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shll.ph", "d,t,4", 0x7c000213, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll.pw", "d,t,6", 0x7c000417, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll.qb", "d,t,3", 0x7c000013, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shll.qh", "d,t,4", 0x7c000217, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.ph", "d,t,4", 0x7c000313, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll_s.pw", "d,t,6", 0x7c000517, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.qh", "d,t,4", 0x7c000317, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.w", "d,t,6", 0x7c000513, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shllv.ob", "d,t,s", 0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.ph", "d,t,s", 0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.pw", "d,t,s", 0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.qb", "d,t,s", 0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.qh", "d,t,s", 0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.ph", "d,t,s", 0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv_s.pw", "d,t,s", 0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.qh", "d,t,s", 0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.w", "d,t,s", 0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shra.ph", "d,t,4", 0x7c000253, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra.pw", "d,t,6", 0x7c000457, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra.qh", "d,t,4", 0x7c000257, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.ph", "d,t,4", 0x7c000353, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra_r.pw", "d,t,6", 0x7c000557, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.qh", "d,t,4", 0x7c000357, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.w", "d,t,6", 0x7c000553, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shrav.ph", "d,t,s", 0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav.pw", "d,t,s", 0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav.qh", "d,t,s", 0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.ph", "d,t,s", 0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav_r.pw", "d,t,s", 0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.qh", "d,t,s", 0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.w", "d,t,s", 0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrl.ob", "d,t,3", 0x7c000057, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shrl.qb", "d,t,3", 0x7c000053, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shrlv.ob", "d,t,s", 0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrlv.qb", "d,t,s", 0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.ph", "d,s,t", 0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.pw", "d,s,t", 0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq.qh", "d,s,t", 0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.ph", "d,s,t", 0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq_s.pw", "d,s,t", 0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.qh", "d,s,t", 0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.w", "d,s,t", 0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu.ob", "d,s,t", 0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu.qb", "d,s,t", 0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu_s.ob", "d,s,t", 0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu_s.qb", "d,s,t", 0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"wrdsp", "s", 0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA, 0, D32 }, +{"wrdsp", "s,8", 0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA, 0, D32 }, +/* MIPS DSP ASE Rev2 */ +{"absq_s.qb", "d,t", 0x7c000052, 0xffe007ff, WR_d|RD_t, 0, D33 }, +{"addu.ph", "d,s,t", 0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addu_s.ph", "d,s,t", 0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh.qb", "d,s,t", 0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh_r.qb", "d,s,t", 0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"append", "t,s,h", 0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"balign", "t,s,I", 0, (int) M_BALIGN, INSN_MACRO, 0, D33 }, +{"balign", "t,s,2", 0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s, 0, D33 }, +{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpa.w.ph", "7,s,t", 0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dps.w.ph", "7,s,t", 0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mul.ph", "d,s,t", 0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mul_s.ph", "d,s,t", 0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_rs.w", "d,s,t", 0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.ph", "d,s,t", 0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.w", "d,s,t", 0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulsa.w.ph", "7,s,t", 0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"prepend", "t,s,h", 0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"shra.qb", "d,t,3", 0x7c000113, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shra_r.qb", "d,t,3", 0x7c000153, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shrav.qb", "d,t,s", 0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrav_r.qb", "d,t,s", 0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrl.ph", "d,t,4", 0x7c000653, 0xfe0007ff, WR_d|RD_t, 0, D33 }, +{"shrlv.ph", "d,t,s", 0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu.ph", "d,s,t", 0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu_s.ph", "d,s,t", 0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh.qb", "d,s,t", 0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh_r.qb", "d,s,t", 0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.ph", "d,s,t", 0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.ph", "d,s,t", 0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.w", "d,s,t", 0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.w", "d,s,t", 0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.ph", "d,s,t", 0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.ph", "d,s,t", 0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.w", "d,s,t", 0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.w", "d,s,t", 0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpax.w.ph", "7,s,t", 0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsx.w.ph", "7,s,t", 0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +/* Move bc0* after mftr and mttr to avoid opcode collision. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +}; + +#define MIPS_NUM_OPCODES \ + ((sizeof mips_builtin_opcodes) / (sizeof (mips_builtin_opcodes[0]))) +const int bfd_mips_num_builtin_opcodes = MIPS_NUM_OPCODES; + +/* const removed from the following to allow for dynamic extensions to the + * built-in instruction set. */ +struct mips_opcode *mips_opcodes = + (struct mips_opcode *) mips_builtin_opcodes; +int bfd_mips_num_opcodes = MIPS_NUM_OPCODES; +#undef MIPS_NUM_OPCODES + +/* Mips instructions are at maximum this many bytes long. */ +#define INSNLEN 4 + + +/* FIXME: These should be shared with gdb somehow. */ + +struct mips_cp0sel_name +{ + unsigned int cp0reg; + unsigned int sel; + const char * const name; +}; + +/* The mips16 registers. */ +static const unsigned int mips16_to_32_reg_map[] = +{ + 16, 17, 2, 3, 4, 5, 6, 7 +}; + +#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] + + +static const char * const mips_gpr_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_gpr_names_oldabi[32] = +{ + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_gpr_names_newabi[32] = +{ + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_fpr_names_numeric[32] = +{ + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +static const char * const mips_fpr_names_32[32] = +{ + "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f", + "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f", + "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f", + "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f" +}; + +static const char * const mips_fpr_names_n32[32] = +{ + "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9", + "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13" +}; + +static const char * const mips_fpr_names_64[32] = +{ + "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" +}; + +static const char * const mips_cp0_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_cp0_names_mips3264[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = +{ + { 4, 1, "c0_contextconfig" }, + { 0, 1, "c0_mvpcontrol" }, + { 0, 2, "c0_mvpconf0" }, + { 0, 3, "c0_mvpconf1" }, + { 1, 1, "c0_vpecontrol" }, + { 1, 2, "c0_vpeconf0" }, + { 1, 3, "c0_vpeconf1" }, + { 1, 4, "c0_yqmask" }, + { 1, 5, "c0_vpeschedule" }, + { 1, 6, "c0_vpeschefback" }, + { 2, 1, "c0_tcstatus" }, + { 2, 2, "c0_tcbind" }, + { 2, 3, "c0_tcrestart" }, + { 2, 4, "c0_tchalt" }, + { 2, 5, "c0_tccontext" }, + { 2, 6, "c0_tcschedule" }, + { 2, 7, "c0_tcschefback" }, + { 5, 1, "c0_pagegrain" }, + { 6, 1, "c0_srsconf0" }, + { 6, 2, "c0_srsconf1" }, + { 6, 3, "c0_srsconf2" }, + { 6, 4, "c0_srsconf3" }, + { 6, 5, "c0_srsconf4" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, +}; + +static const char * const mips_cp0_names_mips3264r2[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = +{ + { 4, 1, "c0_contextconfig" }, + { 5, 1, "c0_pagegrain" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, +}; + +/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */ +static const char * const mips_cp0_names_sb1[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i", + "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = +{ + { 16, 1, "c0_config1" }, + { 18, 1, "c0_watchlo,1" }, + { 19, 1, "c0_watchhi,1" }, + { 22, 0, "c0_perftrace" }, + { 23, 3, "c0_edebug" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 26, 1, "c0_buserr_pa" }, + { 27, 1, "c0_cacheerr_d" }, + { 27, 3, "c0_cacheerr_d_pa" }, + { 28, 1, "c0_datalo_i" }, + { 28, 2, "c0_taglo_d" }, + { 28, 3, "c0_datalo_d" }, + { 29, 1, "c0_datahi_i" }, + { 29, 2, "c0_taghi_d" }, + { 29, 3, "c0_datahi_d" }, +}; + +static const char * const mips_hwr_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_hwr_names_mips3264r2[32] = +{ + "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", + "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +struct mips_abi_choice +{ + const char *name; + const char * const *gpr_names; + const char * const *fpr_names; +}; + +struct mips_abi_choice mips_abi_choices[] = +{ + { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, + { "32", mips_gpr_names_oldabi, mips_fpr_names_32 }, + { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 }, + { "64", mips_gpr_names_newabi, mips_fpr_names_64 }, +}; + +struct mips_arch_choice +{ + const char *name; + int bfd_mach_valid; + unsigned long bfd_mach; + int processor; + int isa; + const char * const *cp0_names; + const struct mips_cp0sel_name *cp0sel_names; + unsigned int cp0sel_names_len; + const char * const *hwr_names; +}; + +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4111 4111 +#define bfd_mach_mips4120 4120 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips5400 5400 +#define bfd_mach_mips5500 5500 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips7000 7000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips9000 9000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips12000 12000 +#define bfd_mach_mips16 16 +#define bfd_mach_mips5 5 +#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ +#define bfd_mach_mipsisa32 32 +#define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa64 64 +#define bfd_mach_mipsisa64r2 65 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +const struct mips_arch_choice mips_arch_choices[] = +{ + { "numeric", 0, 0, 0, 0, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs. + Note that MIPS-3D and MDMX are not applicable to MIPS32. (See + _MIPS32 Architecture For Programmers Volume I: Introduction to the + MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95), + page 1. */ + { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32, + ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, + (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 + | INSN_MIPS3D | INSN_MT), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */ + { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64, + ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2, + (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2 + | INSN_DSP64 | INSN_MT | INSN_MDMX), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, + ISA_MIPS64 | INSN_MIPS3D | INSN_SB1, + mips_cp0_names_sb1, + mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1), + mips_hwr_names_numeric }, + + /* This entry, mips16, is here only for ISA/processor selection; do + not print its name. */ + { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, +}; + +/* ISA and processor type to disassemble for, and register names to use. + set_default_mips_dis_options and parse_mips_dis_options fill in these + values. */ +static int mips_processor; +static int mips_isa; +static const char * const *mips_gpr_names; +static const char * const *mips_fpr_names; +static const char * const *mips_cp0_names; +static const struct mips_cp0sel_name *mips_cp0sel_names; +static int mips_cp0sel_names_len; +static const char * const *mips_hwr_names; + +/* Other options */ +static int no_aliases; /* If set disassemble as most general inst. */ + +static const struct mips_abi_choice * +choose_abi_by_name (const char *name, unsigned int namelen) +{ + const struct mips_abi_choice *c; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) + if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 + && strlen (mips_abi_choices[i].name) == namelen) + c = &mips_abi_choices[i]; + + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_name (const char *name, unsigned int namelen) +{ + const struct mips_arch_choice *c = NULL; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 + && strlen (mips_arch_choices[i].name) == namelen) + c = &mips_arch_choices[i]; + + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_number (unsigned long mach) +{ + static unsigned long hint_bfd_mach; + static const struct mips_arch_choice *hint_arch_choice; + const struct mips_arch_choice *c; + unsigned int i; + + /* We optimize this because even if the user specifies no + flags, this will be done for every instruction! */ + if (hint_bfd_mach == mach + && hint_arch_choice != NULL + && hint_arch_choice->bfd_mach == hint_bfd_mach) + return hint_arch_choice; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + { + if (mips_arch_choices[i].bfd_mach_valid + && mips_arch_choices[i].bfd_mach == mach) + { + c = &mips_arch_choices[i]; + hint_bfd_mach = mach; + hint_arch_choice = c; + } + } + return c; +} + +static void +set_default_mips_dis_options (struct disassemble_info *info) +{ + const struct mips_arch_choice *chosen_arch; + + /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names, + and numeric FPR, CP0 register, and HWR names. */ + mips_isa = ISA_MIPS3; + mips_processor = CPU_R3000; + mips_gpr_names = mips_gpr_names_oldabi; + mips_fpr_names = mips_fpr_names_numeric; + mips_cp0_names = mips_cp0_names_numeric; + mips_cp0sel_names = NULL; + mips_cp0sel_names_len = 0; + mips_hwr_names = mips_hwr_names_numeric; + no_aliases = 0; + + /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ +#if 0 + if (info->flavour == bfd_target_elf_flavour && info->section != NULL) + { + Elf_Internal_Ehdr *header; + + header = elf_elfheader (info->section->owner); + if (is_newabi (header)) + mips_gpr_names = mips_gpr_names_newabi; + } +#endif + + /* Set ISA, architecture, and cp0 register names as best we can. */ +#if !defined(SYMTAB_AVAILABLE) && 0 + /* This is running out on a target machine, not in a host tool. + FIXME: Where does mips_target_info come from? */ + target_processor = mips_target_info.processor; + mips_isa = mips_target_info.isa; +#else + chosen_arch = choose_arch_by_number (info->mach); + if (chosen_arch != NULL) + { + mips_processor = chosen_arch->processor; + mips_isa = chosen_arch->isa; + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } +#endif +} + +static void +parse_mips_dis_option (const char *option, unsigned int len) +{ + unsigned int i, optionlen, vallen; + const char *val; + const struct mips_abi_choice *chosen_abi; + const struct mips_arch_choice *chosen_arch; + + /* Look for the = that delimits the end of the option name. */ + for (i = 0; i < len; i++) + { + if (option[i] == '=') + break; + } + if (i == 0) /* Invalid option: no name before '='. */ + return; + if (i == len) /* Invalid option: no '='. */ + return; + if (i == (len - 1)) /* Invalid option: no value after '='. */ + return; + + optionlen = i; + val = option + (optionlen + 1); + vallen = len - (optionlen + 1); + + if (strncmp("gpr-names", option, optionlen) == 0 + && strlen("gpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_gpr_names = chosen_abi->gpr_names; + return; + } + + if (strncmp("fpr-names", option, optionlen) == 0 + && strlen("fpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_fpr_names = chosen_abi->fpr_names; + return; + } + + if (strncmp("cp0-names", option, optionlen) == 0 + && strlen("cp0-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + } + return; + } + + if (strncmp("hwr-names", option, optionlen) == 0 + && strlen("hwr-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + mips_hwr_names = chosen_arch->hwr_names; + return; + } + + if (strncmp("reg-names", option, optionlen) == 0 + && strlen("reg-names") == optionlen) + { + /* We check both ABI and ARCH here unconditionally, so + that "numeric" will do the desirable thing: select + numeric register names for all registers. Other than + that, a given name probably won't match both. */ + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + { + mips_gpr_names = chosen_abi->gpr_names; + mips_fpr_names = chosen_abi->fpr_names; + } + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } + return; + } + + /* Invalid option. */ +} + +static void +parse_mips_dis_options (const char *options) +{ + const char *option_end; + + if (options == NULL) + return; + + while (*options != '\0') + { + /* Skip empty options. */ + if (*options == ',') + { + options++; + continue; + } + + /* We know that *options is neither NUL or a comma. */ + option_end = options + 1; + while (*option_end != ',' && *option_end != '\0') + option_end++; + + parse_mips_dis_option (options, option_end - options); + + /* Go on to the next one. If option_end points to a comma, it + will be skipped above. */ + options = option_end; + } +} + +static const struct mips_cp0sel_name * +lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names, + unsigned int len, + unsigned int cp0reg, + unsigned int sel) +{ + unsigned int i; + + for (i = 0; i < len; i++) + if (names[i].cp0reg == cp0reg && names[i].sel == sel) + return &names[i]; + return NULL; +} + +/* Print insn arguments for 32/64-bit code. */ + +static void +print_insn_args (const char *d, + register unsigned long int l, + bfd_vma pc, + struct disassemble_info *info, + const struct mips_opcode *opp) +{ + int op, delta; + unsigned int lsb, msb, msbd; + + lsb = 0; + + for (; *d != '\0'; d++) + { + switch (*d) + { + case ',': + case '(': + case ')': + case '[': + case ']': + (*info->fprintf_func) (info->stream, "%c", *d); + break; + + case '+': + /* Extension character; switch for second char. */ + d++; + switch (*d) + { + case '\0': + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, incomplete extension sequence (+)")); + return; + + case 'A': + lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'B': + msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case '1': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI1) & OP_MASK_UDI1); + break; + + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI2) & OP_MASK_UDI2); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI3) & OP_MASK_UDI3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI4) & OP_MASK_UDI4); + break; + + case 'C': + case 'H': + msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + case 'D': + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mtcN (et al.), to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + + case 'E': + lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'F': + msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case 'G': + msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + case 't': /* Coprocessor 0 reg name */ + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RT) & + OP_MASK_RT]); + break; + + case 'T': /* Coprocessor 0 reg name */ + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mftc0, to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined extension sequence (+%c)"), + *d); + return; + } + break; + + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_BP) & OP_MASK_BP); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA3) & OP_MASK_SA3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA4) & OP_MASK_SA4); + break; + + case '5': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_IMM8) & OP_MASK_IMM8); + break; + + case '6': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RS) & OP_MASK_RS); + break; + + case '7': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); + break; + + case '8': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); + break; + + case '9': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); + break; + + case '0': /* dsp 6-bit signed immediate in bit 20 */ + delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); + if (delta & 0x20) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case ':': /* dsp 7-bit signed immediate in bit 19 */ + delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); + if (delta & 0x40) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT_7; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '\'': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); + break; + + case '@': /* dsp 10-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) /* test sign bit */ + delta |= ~OP_MASK_IMM10; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '!': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_U) & OP_MASK_MT_U); + break; + + case '$': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_H) & OP_MASK_MT_H); + break; + + case '*': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); + break; + + case '&': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); + break; + + case 'g': + /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 's': + case 'b': + case 'r': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); + break; + + case 't': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'i': + case 'u': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); + break; + + case 'j': /* Same as i, but sign-extended. */ + case 'o': + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + (*info->fprintf_func) (info->stream, "%d", + delta); + break; + + case 'h': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_PREFX) + & OP_MASK_PREFX)); + break; + + case 'k': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_CACHE) + & OP_MASK_CACHE)); + break; + + case 'a': + info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + /* For gdb disassembler, force odd address on jalx. */ + if (info->flavour == bfd_target_unknown_flavour + && strcmp (opp->name, "jalx") == 0) + info->target |= 1; + (*info->print_address_func) (info->target, info); + break; + + case 'p': + /* Sign extend the displacement. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + + case 'd': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'U': + { + /* First check for both rd and rt being equal. */ + unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else + { + /* If one is zero use the other. */ + if (reg == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else /* Bogus, result depends on processor. */ + (*info->fprintf_func) (info->stream, "%s or %s", + mips_gpr_names[reg], + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case '<': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); + break; + + case 'c': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE) & OP_MASK_CODE); + break; + + case 'q': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE2) & OP_MASK_CODE2); + break; + + case 'C': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_COPZ) & OP_MASK_COPZ); + break; + + case 'B': + (*info->fprintf_func) (info->stream, "0x%lx", + + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); + break; + + case 'S': + case 'V': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'T': + case 'W': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); + break; + + case 'E': + /* Coprocessor register for lwcN instructions, et al. + + Note that there is no load/store cp0 instructions, and + that FPU (cp1) instructions disassemble this field using + 'T' format. Therefore, until we gain understanding of + cp2 register names, we can simply print the register + numbers. */ + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RT) & OP_MASK_RT); + break; + + case 'G': + /* Coprocessor register for mtcN instructions, et al. Note + that FPU (cp1) instructions disassemble this field using + 'S' format. Therefore, we only need to worry about cp0, + cp2, and cp3. */ + op = (l >> OP_SH_OP) & OP_MASK_OP; + if (op == OP_OP_COP0) + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); + else + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 'K': + (*info->fprintf_func) (info->stream, "%s", + mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'N': + (*info->fprintf_func) (info->stream, + ((opp->pinfo & (FP_D | FP_S)) != 0 + ? "$fcc%ld" : "$cc%ld"), + (l >> OP_SH_BCC) & OP_MASK_BCC); + break; + + case 'M': + (*info->fprintf_func) (info->stream, "$fcc%ld", + (l >> OP_SH_CCC) & OP_MASK_CCC); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); + break; + + case 'e': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); + break; + + case '%': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_SEL) & OP_MASK_SEL); + break; + + case 'O': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_ALN) & OP_MASK_ALN); + break; + + case 'Q': + { + unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + + if ((vsel & 0x10) == 0) + { + int fmt; + + vsel &= 0x0f; + for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) + if ((vsel & 1) == 0) + break; + (*info->fprintf_func) (info->stream, "$v%ld[%d]", + (l >> OP_SH_FT) & OP_MASK_FT, + vsel >> 1); + } + else if ((vsel & 0x08) == 0) + { + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + } + else + { + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_FT) & OP_MASK_FT); + } + } + break; + + case 'X': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FD) & OP_MASK_FD); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FS) & OP_MASK_FS); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined modifier(%c)"), + *d); + return; + } + } +} + +/* Check if the object uses NewABI conventions. */ +#if 0 +static int +is_newabi (header) + Elf_Internal_Ehdr *header; +{ + /* There are no old-style ABIs which use 64-bit ELF. */ + if (header->e_ident[EI_CLASS] == ELFCLASS64) + return 1; + + /* If a 32-bit ELF file, n32 is a new-style ABI. */ + if ((header->e_flags & EF_MIPS_ABI2) != 0) + return 1; + + return 0; +} +#endif + +/* Print the mips instruction at address MEMADDR in debugged memory, + on using INFO. Returns length of the instruction, in bytes, which is + always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if + this is little-endian code. */ + +static int +print_insn_mips (bfd_vma memaddr, + unsigned long int word, + struct disassemble_info *info) +{ + const struct mips_opcode *op; + static bfd_boolean init = 0; + static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; + + /* Build a hash table to shorten the search time. */ + if (! init) + { + unsigned int i; + + for (i = 0; i <= OP_MASK_OP; i++) + { + for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo == INSN_MACRO + || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) + continue; + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) + { + mips_hash[i] = op; + break; + } + } + } + + init = 1; + } + + info->bytes_per_chunk = INSNLEN; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; + if (op != NULL) + { + for (; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (word & op->mask) == op->match) + { + const char *d; + + /* We always allow to disassemble the jalx instruction. */ + if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor) + && strcmp (op->name, "jalx")) + continue; + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_jsr; + else + info->insn_type = dis_branch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_condjsr; + else + info->insn_type = dis_condbranch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_STORE_MEMORY + | INSN_LOAD_MEMORY_DELAY)) != 0) + info->insn_type = dis_dref; + + (*info->fprintf_func) (info->stream, "%s", op->name); + + d = op->args; + if (d != NULL && *d != '\0') + { + (*info->fprintf_func) (info->stream, "\t"); + print_insn_args (d, word, memaddr, info, op); + } + + return INSNLEN; + } + } + } + + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream, "0x%lx", word); + return INSNLEN; +} + +/* In an environment where we do not know the symbol type of the + instruction we are forced to assume that the low order bit of the + instructions' address may mark it as a mips16 instruction. If we + are single stepping, or the pc is within the disassembled function, + this works. Otherwise, we need a clue. Sometimes. */ + +static int +_print_insn_mips (bfd_vma memaddr, + struct disassemble_info *info, + enum bfd_endian endianness) +{ + bfd_byte buffer[INSNLEN]; + int status; + + set_default_mips_dis_options (info); + parse_mips_dis_options (info->disassembler_options); + +#if 0 +#if 1 + /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */ + /* Only a few tools will work this way. */ + if (memaddr & 0x01) + return print_insn_mips16 (memaddr, info); +#endif + +#if SYMTAB_AVAILABLE + if (info->mach == bfd_mach_mips16 + || (info->flavour == bfd_target_elf_flavour + && info->symbols != NULL + && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other + == STO_MIPS16))) + return print_insn_mips16 (memaddr, info); +#endif +#endif + + status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info); + if (status == 0) + { + unsigned long insn; + + if (endianness == BFD_ENDIAN_BIG) + insn = (unsigned long) bfd_getb32 (buffer); + else + insn = (unsigned long) bfd_getl32 (buffer); + + return print_insn_mips (memaddr, insn, info); + } + else + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } +} + +int +print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info) +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG); +} + +int +print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info) +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); +} + +/* Disassemble mips16 instructions. */ +#if 0 +static int +print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) +{ + int status; + bfd_byte buffer[2]; + int length; + int insn; + bfd_boolean use_extend; + int extend = 0; + const struct mips_opcode *op, *opend; + + info->bytes_per_chunk = 2; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + length = 2; + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Handle the extend opcode specially. */ + use_extend = FALSE; + if ((insn & 0xf800) == 0xf000) + { + use_extend = TRUE; + extend = insn & 0x7ff; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Check for an extend opcode followed by an extend opcode. */ + if ((insn & 0xf800) == 0xf000) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length; + } + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + + opend = mips16_opcodes + bfd_mips16_num_opcodes; + for (op = mips16_opcodes; op < opend; op++) + { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match) + { + const char *s; + + if (strchr (op->args, 'a') != NULL) + { + if (use_extend) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length - 2; + } + + use_extend = FALSE; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, + info); + if (status == 0) + { + use_extend = TRUE; + if (info->endian == BFD_ENDIAN_BIG) + extend = bfd_getb16 (buffer); + else + extend = bfd_getl16 (buffer); + length += 2; + } + } + + (*info->fprintf_func) (info->stream, "%s", op->name); + if (op->args[0] != '\0') + (*info->fprintf_func) (info->stream, "\t"); + + for (s = op->args; *s != '\0'; s++) + { + if (*s == ',' + && s[1] == 'w' + && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) + == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + if (*s == ',' + && s[1] == 'v' + && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) + == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr, + info); + } + + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + info->branch_delay_insns = 1; + if (info->insn_type != dis_jsr) + info->insn_type = dis_branch; + } + + return length; + } + } + + if (use_extend) + (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000); + (*info->fprintf_func) (info->stream, "0x%x", insn); + info->insn_type = dis_noninsn; + + return length; +} + +/* Disassemble an operand for a mips16 instruction. */ + +static void +print_mips16_insn_arg (char type, + const struct mips_opcode *op, + int l, + bfd_boolean use_extend, + int extend, + bfd_vma memaddr, + struct disassemble_info *info) +{ + switch (type) + { + case ',': + case '(': + case ')': + (*info->fprintf_func) (info->stream, "%c", type); + break; + + case 'y': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY))); + break; + + case 'x': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX))); + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ))); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z))); + break; + + case '0': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "$pc"); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]); + break; + + case 'X': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[((l >> MIPS16OP_SH_REGR32) + & MIPS16OP_MASK_REGR32)]); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); + break; + + case '<': + case '>': + case '[': + case ']': + case '4': + case '5': + case 'H': + case 'W': + case 'D': + case 'j': + case '6': + case '8': + case 'V': + case 'C': + case 'U': + case 'k': + case 'K': + case 'p': + case 'q': + case 'A': + case 'B': + case 'E': + { + int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; + + shift = 0; + signedp = 0; + extbits = 16; + pcrel = 0; + extu = 0; + branch = 0; + switch (type) + { + case '<': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 5; + extu = 1; + break; + case '>': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 5; + extu = 1; + break; + case '[': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 6; + extu = 1; + break; + case ']': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 6; + extu = 1; + break; + case '4': + nbits = 4; + immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; + signedp = 1; + extbits = 15; + break; + case '5': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 1; + break; + case 'H': + nbits = 5; + shift = 1; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 2; + break; + case 'W': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 + && (op->pinfo & MIPS16_INSN_READ_SP) == 0) + { + info->insn_type = dis_dref; + info->data_size = 4; + } + break; + case 'D': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'j': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + signedp = 1; + break; + case '6': + nbits = 6; + immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + break; + case '8': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + break; + case 'V': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + /* FIXME: This might be lw, or it might be addiu to $sp or + $pc. We assume it's load. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'C': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'U': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + extu = 1; + break; + case 'k': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'K': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'p': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_condbranch; + break; + case 'q': + nbits = 11; + immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_branch; + break; + case 'A': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + pcrel = 1; + /* FIXME: This can be lw or la. We assume it is lw. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'B': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'E': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + break; + default: + abort (); + } + + if (! use_extend) + { + if (signedp && immed >= (1 << (nbits - 1))) + immed -= 1 << nbits; + immed <<= shift; + if ((type == '<' || type == '>' || type == '[' || type == ']') + && immed == 0) + immed = 8; + } + else + { + if (extbits == 16) + immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); + else if (extbits == 15) + immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); + else + immed = ((extend >> 6) & 0x1f) | (extend & 0x20); + immed &= (1 << extbits) - 1; + if (! extu && immed >= (1 << (extbits - 1))) + immed -= 1 << extbits; + } + + if (! pcrel) + (*info->fprintf_func) (info->stream, "%d", immed); + else + { + bfd_vma baseaddr; + + if (branch) + { + immed *= 2; + baseaddr = memaddr + 2; + } + else if (use_extend) + baseaddr = memaddr - 2; + else + { + int status; + bfd_byte buffer[2]; + + baseaddr = memaddr; + + /* If this instruction is in the delay slot of a jr + instruction, the base address is the address of the + jr instruction. If it is in the delay slot of jalr + instruction, the base address is the address of the + jalr instruction. This test is unreliable: we have + no way of knowing whether the previous word is + instruction or data. */ + status = (*info->read_memory_func) (memaddr - 4, buffer, 2, + info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else + { + status = (*info->read_memory_func) (memaddr - 2, buffer, + 2, info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf81f) == 0xe800)) + baseaddr = memaddr - 2; + } + } + info->target = (baseaddr & ~((1 << shift) - 1)) + immed; + if (pcrel && branch + && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + info->target |= 1; + (*info->print_address_func) (info->target, info); + } + } + break; + + case 'a': + { + int jalx = l & 0x400; + + if (! use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + if (!jalx && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + l |= 1; + } + info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l; + (*info->print_address_func) (info->target, info); + info->insn_type = dis_jsr; + info->branch_delay_insns = 1; + break; + + case 'l': + case 'L': + { + int need_comma, amask, smask; + + need_comma = 0; + + l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + + amask = (l >> 3) & 7; + + if (amask > 0 && amask < 5) + { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (amask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[amask + 3]); + need_comma = 1; + } + + smask = (l >> 1) & 3; + if (smask == 3) + { + (*info->fprintf_func) (info->stream, "%s??", + need_comma ? "," : ""); + need_comma = 1; + } + else if (smask > 0) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[16]); + if (smask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[smask + 15]); + need_comma = 1; + } + + if (l & 1) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[31]); + need_comma = 1; + } + + if (amask == 5 || amask == 6) + { + (*info->fprintf_func) (info->stream, "%s$f0", + need_comma ? "," : ""); + if (amask == 6) + (*info->fprintf_func) (info->stream, "-$f1"); + } + } + break; + + case 'm': + case 'M': + /* MIPS16e save/restore. */ + { + int need_comma = 0; + int amask, args, statics; + int nsreg, smask; + int framesz; + int i, j; + + l = l & 0x7f; + if (use_extend) + l |= extend << 16; + + amask = (l >> 16) & 0xf; + if (amask == MIPS16_ALL_ARGS) + { + args = 4; + statics = 0; + } + else if (amask == MIPS16_ALL_STATICS) + { + args = 0; + statics = 4; + } + else + { + args = amask >> 2; + statics = amask & 3; + } + + if (args > 0) { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (args > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[4 + args - 1]); + need_comma = 1; + } + + framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; + if (framesz == 0 && !use_extend) + framesz = 128; + + (*info->fprintf_func) (info->stream, "%s%d", + need_comma ? "," : "", + framesz); + + if (l & 0x40) /* $ra */ + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]); + + nsreg = (l >> 24) & 0x7; + smask = 0; + if (l & 0x20) /* $s0 */ + smask |= 1 << 0; + if (l & 0x10) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + /* Find first set static reg bit. */ + for (i = 0; i < 9; i++) + { + if (smask & (1 << i)) + { + (*info->fprintf_func) (info->stream, ",%s", + mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + } + + /* Statics $ax - $a3. */ + if (statics == 1) + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]); + else if (statics > 0) + (*info->fprintf_func) (info->stream, ",%s-%s", + mips_gpr_names[7 - statics + 1], + mips_gpr_names[7]); + } + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) + (info->stream, + _("# internal disassembler error, unrecognised modifier (%c)"), + type); + abort (); + } +} + +void +print_mips_disassembler_options (FILE *stream) +{ + unsigned int i; + + fprintf (stream, _("\n\ +The following MIPS specific disassembler options are supported for use\n\ +with the -M switch (multiple options should be separated by commas):\n")); + + fprintf (stream, _("\n\ + gpr-names=ABI Print GPR names according to specified ABI.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + fpr-names=ABI Print FPR names according to specified ABI.\n\ + Default: numeric.\n")); + + fprintf (stream, _("\n\ + cp0-names=ARCH Print CP0 register names according to\n\ + specified architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + hwr-names=ARCH Print HWR names according to specified \n\ + architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + reg-names=ABI Print GPR and FPR names according to\n\ + specified ABI.\n")); + + fprintf (stream, _("\n\ + reg-names=ARCH Print CP0 register and HWR names according to\n\ + specified architecture.\n")); + + fprintf (stream, _("\n\ + For the options above, the following values are supported for \"ABI\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) + fprintf (stream, " %s", mips_abi_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n\ + For the options above, The following values are supported for \"ARCH\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) + if (*mips_arch_choices[i].name != '\0') + fprintf (stream, " %s", mips_arch_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n")); +} +#endif diff --git a/qemu/qemu-git/.svn/text-base/mips.ld.svn-base b/qemu/qemu-git/.svn/text-base/mips.ld.svn-base new file mode 100644 index 0000000..4294761 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/mips.ld.svn-base @@ -0,0 +1,224 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", + "elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(__start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x47ff041f + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/.svn/text-base/module.h.svn-base b/qemu/qemu-git/.svn/text-base/module.h.svn-base new file mode 100644 index 0000000..9263f1c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/module.h.svn-base @@ -0,0 +1,38 @@ +/* + * QEMU Module Infrastructure + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MODULE_H +#define QEMU_MODULE_H + +/* This should not be used directly. Use block_init etc. instead. */ +#define module_init(function, type) \ +static void __attribute__((constructor)) do_qemu_init_ ## function(void) { \ + register_module_init(function, type); \ +} + +typedef enum { + MODULE_INIT_BLOCK, + MODULE_INIT_DEVICE, + MODULE_INIT_MACHINE, + MODULE_INIT_MAX +} module_init_type; + +#define block_init(function) module_init(function, MODULE_INIT_BLOCK) +#define device_init(function) module_init(function, MODULE_INIT_DEVICE) +#define machine_init(function) module_init(function, MODULE_INIT_MACHINE) + +void register_module_init(void (*fn)(void), module_init_type type); + +void module_call_init(module_init_type type); + +#endif diff --git a/qemu/qemu-git/.svn/text-base/osdep.h.svn-base b/qemu/qemu-git/.svn/text-base/osdep.h.svn-base new file mode 100644 index 0000000..75b5816 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/osdep.h.svn-base @@ -0,0 +1,108 @@ +#ifndef QEMU_OSDEP_H +#define QEMU_OSDEP_H + +#include +#include +#ifdef __OpenBSD__ +#include +#include +#endif + +#ifndef _WIN32 +#include +#endif + +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef likely +#if __GNUC__ < 3 +#define __builtin_expect(x, n) (x) +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifdef CONFIG_NEED_OFFSETOF +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) +#endif +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *__mptr = (ptr); \ + (type *) ((char *) __mptr - offsetof(type, member));}) +#endif + +/* Convert from a base type to a parent type, with compile time checking. */ +#ifdef __GNUC__ +#define DO_UPCAST(type, field, dev) ( __extension__ ( { \ + char __attribute__((unused)) offset_must_be_zero[ \ + -offsetof(type, field)]; \ + container_of(dev, type, field);})) +#else +#define DO_UPCAST(type, field, dev) container_of(dev, type, field) +#endif + +#define typeof_field(type, field) typeof(((type *)0)->field) +#define type_check(t1,t2) ((t1*)0 - (t2*)0) + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef always_inline +#if !((__GNUC__ < 3) || defined(__APPLE__)) +#ifdef __OPTIMIZE__ +#define inline __attribute__ (( always_inline )) __inline__ +#endif +#endif +#else +#define inline always_inline +#endif + +#ifdef __i386__ +#define REGPARM __attribute((regparm(3))) +#else +#define REGPARM +#endif + +#define qemu_printf printf + +#if defined (__GNUC__) && defined (__GNUC_MINOR__) +# define QEMU_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define QEMU_GNUC_PREREQ(maj, min) 0 +#endif + +void *qemu_memalign(size_t alignment, size_t size); +void *qemu_vmalloc(size_t size); +void qemu_vfree(void *ptr); + +int qemu_create_pidfile(const char *filename); + +#ifdef _WIN32 +int ffs(int i); + +typedef struct { + long tv_sec; + long tv_usec; +} qemu_timeval; +int qemu_gettimeofday(qemu_timeval *tp); +#else +typedef struct timeval qemu_timeval; +#define qemu_gettimeofday(tp) gettimeofday(tp, NULL); +#endif /* !_WIN32 */ + +#endif diff --git a/qemu/qemu-git/.svn/text-base/ppc-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/ppc-dis.c.svn-base new file mode 100644 index 0000000..ffdbec1 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/ppc-dis.c.svn-base @@ -0,0 +1,5412 @@ +/* ppc-dis.c -- Disassemble PowerPC instructions + Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ +#include "dis-asm.h" +#define BFD_DEFAULT_TARGET_SIZE 64 + +/* ppc.h -- Header file for PowerPC opcode table + Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ + +/* The opcode table is an array of struct powerpc_opcode. */ + +struct powerpc_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned long opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned long mask; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The defined values + are listed below. */ + unsigned long flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[8]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct powerpc_opcode powerpc_opcodes[]; +extern const int powerpc_num_opcodes; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* Opcode is defined for the PowerPC architecture. */ +#define PPC_OPCODE_PPC 1 + +/* Opcode is defined for the POWER (RS/6000) architecture. */ +#define PPC_OPCODE_POWER 2 + +/* Opcode is defined for the POWER2 (Rios 2) architecture. */ +#define PPC_OPCODE_POWER2 4 + +/* Opcode is only defined on 32 bit architectures. */ +#define PPC_OPCODE_32 8 + +/* Opcode is only defined on 64 bit architectures. */ +#define PPC_OPCODE_64 0x10 + +/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 + is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, + but it also supports many additional POWER instructions. */ +#define PPC_OPCODE_601 0x20 + +/* Opcode is supported in both the Power and PowerPC architectures + (ie, compiler's -mcpu=common or assembler's -mcom). */ +#define PPC_OPCODE_COMMON 0x40 + +/* Opcode is supported for any Power or PowerPC platform (this is + for the assembler's -many option, and it eliminates duplicates). */ +#define PPC_OPCODE_ANY 0x80 + +/* Opcode is supported as part of the 64-bit bridge. */ +#define PPC_OPCODE_64_BRIDGE 0x100 + +/* Opcode is supported by Altivec Vector Unit */ +#define PPC_OPCODE_ALTIVEC 0x200 + +/* Opcode is supported by PowerPC 403 processor. */ +#define PPC_OPCODE_403 0x400 + +/* Opcode is supported by PowerPC BookE processor. */ +#define PPC_OPCODE_BOOKE 0x800 + +/* Opcode is only supported by 64-bit PowerPC BookE processor. */ +#define PPC_OPCODE_BOOKE64 0x1000 + +/* Opcode is supported by PowerPC 440 processor. */ +#define PPC_OPCODE_440 0x2000 + +/* Opcode is only supported by Power4 architecture. */ +#define PPC_OPCODE_POWER4 0x4000 + +/* Opcode isn't supported by Power4 architecture. */ +#define PPC_OPCODE_NOPOWER4 0x8000 + +/* Opcode is only supported by POWERPC Classic architecture. */ +#define PPC_OPCODE_CLASSIC 0x10000 + +/* Opcode is only supported by e500x2 Core. */ +#define PPC_OPCODE_SPE 0x20000 + +/* Opcode is supported by e500x2 Integer select APU. */ +#define PPC_OPCODE_ISEL 0x40000 + +/* Opcode is an e500 SPE floating point instruction. */ +#define PPC_OPCODE_EFS 0x80000 + +/* Opcode is supported by branch locking APU. */ +#define PPC_OPCODE_BRLOCK 0x100000 + +/* Opcode is supported by performance monitor APU. */ +#define PPC_OPCODE_PMR 0x200000 + +/* Opcode is supported by cache locking APU. */ +#define PPC_OPCODE_CACHELCK 0x400000 + +/* Opcode is supported by machine check APU. */ +#define PPC_OPCODE_RFMCI 0x800000 + +/* Opcode is only supported by Power5 architecture. */ +#define PPC_OPCODE_POWER5 0x1000000 + +/* Opcode is supported by PowerPC e300 family. */ +#define PPC_OPCODE_E300 0x2000000 + +/* Opcode is only supported by Power6 architecture. */ +#define PPC_OPCODE_POWER6 0x4000000 + +/* Opcode is only supported by PowerPC Cell family. */ +#define PPC_OPCODE_CELL 0x8000000 + +/* A macro to extract the major opcode from an instruction. */ +#define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* The operands table is an array of struct powerpc_operand. */ + +struct powerpc_operand +{ + /* A bitmask of bits in the operand. */ + unsigned int bitm; + + /* How far the operand is left shifted in the instruction. + -1 to indicate that BITM and SHIFT cannot be used to determine + where the operand goes in the insn. */ + int shift; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & o->bitm) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the operand value). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned long (*insert) + (unsigned long instruction, long op, int dialect, const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = (i >> o->shift) & o->bitm; + if ((o->flags & PPC_OPERAND_SIGNED) != 0) + sign_extend (op); + (i is the instruction, o is a pointer to this structure, and op + is the result). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + long (*extract) (unsigned long instruction, int dialect, int *invalid); + + /* One bit syntax flags. */ + unsigned long flags; +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct powerpc_operand powerpc_operands[]; +extern const unsigned int num_powerpc_operands; + +/* Values defined for the flags field of a struct powerpc_operand. */ + +/* This operand takes signed values. */ +#define PPC_OPERAND_SIGNED (0x1) + +/* This operand takes signed values, but also accepts a full positive + range of values when running in 32 bit mode. That is, if bits is + 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, + this flag is ignored. */ +#define PPC_OPERAND_SIGNOPT (0x2) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics such as mr, for which two + operands fields are identical. The assembler should call the + insert function with any op value. The disassembler should call + the extract function, ignore the return value, and check the value + placed in the valid argument. */ +#define PPC_OPERAND_FAKE (0x4) + +/* The next operand should be wrapped in parentheses rather than + separated from this one by a comma. This is used for the load and + store instructions which want their operands to look like + reg,displacement(reg) + */ +#define PPC_OPERAND_PARENS (0x8) + +/* This operand may use the symbolic names for the CR fields, which + are + lt 0 gt 1 eq 2 so 3 un 3 + cr0 0 cr1 1 cr2 2 cr3 3 + cr4 4 cr5 5 cr6 6 cr7 7 + These may be combined arithmetically, as in cr2*4+gt. These are + only supported on the PowerPC, not the POWER. */ +#define PPC_OPERAND_CR (0x10) + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define PPC_OPERAND_GPR (0x20) + +/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0. */ +#define PPC_OPERAND_GPR_0 (0x40) + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define PPC_OPERAND_FPR (0x80) + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_RELATIVE (0x100) + +/* This operand is an absolute branch address. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_ABSOLUTE (0x200) + +/* This operand is optional, and is zero if omitted. This is used for + example, in the optional BF field in the comparison instructions. The + assembler must count the number of operands remaining on the line, + and the number of operands remaining for the opcode, and decide + whether this operand is present or not. The disassembler should + print this operand out only if it is not zero. */ +#define PPC_OPERAND_OPTIONAL (0x400) + +/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand + is omitted, then for the next operand use this operand value plus + 1, ignoring the next operand field for the opcode. This wretched + hack is needed because the Power rotate instructions can take + either 4 or 5 operands. The disassembler should print this operand + out regardless of the PPC_OPERAND_OPTIONAL field. */ +#define PPC_OPERAND_NEXT (0x800) + +/* This operand should be regarded as a negative number for the + purposes of overflow checking (i.e., the normal most negative + number is disallowed and one more than the normal most positive + number is allowed). This flag will only be set for a signed + operand. */ +#define PPC_OPERAND_NEGATIVE (0x1000) + +/* This operand names a vector unit register. The disassembler + prints these with a leading 'v'. */ +#define PPC_OPERAND_VR (0x2000) + +/* This operand is for the DS field in a DS form instruction. */ +#define PPC_OPERAND_DS (0x4000) + +/* This operand is for the DQ field in a DQ form instruction. */ +#define PPC_OPERAND_DQ (0x8000) + +/* Valid range of operand is 0..n rather than 0..n-1. */ +#define PPC_OPERAND_PLUS1 (0x10000) + +/* The POWER and PowerPC assemblers use a few macros. We keep them + with the operands table for simplicity. The macro table is an + array of struct powerpc_macro. */ + +struct powerpc_macro +{ + /* The macro name. */ + const char *name; + + /* The number of operands the macro takes. */ + unsigned int operands; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The values are the + same as those for the struct powerpc_opcode flags field. */ + unsigned long flags; + + /* A format string to turn the macro into a normal instruction. + Each %N in the string is replaced with operand number N (zero + based). */ + const char *format; +}; + +extern const struct powerpc_macro powerpc_macros[]; +extern const int powerpc_num_macros; + +/* ppc-opc.c -- PowerPC opcode list + Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. + If not, see . */ + +/* This file holds the PowerPC opcode table. The opcode table + includes almost all of the extended instruction mnemonics. This + permits the disassembler to use them, and simplifies the assembler + logic, at the cost of increasing the table size. The table is + strictly constant data, so the compiler should be able to put it in + the .text section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* Local insertion and extraction functions. */ + +static unsigned long insert_bat (unsigned long, long, int, const char **); +static long extract_bat (unsigned long, int, int *); +static unsigned long insert_bba (unsigned long, long, int, const char **); +static long extract_bba (unsigned long, int, int *); +static unsigned long insert_bdm (unsigned long, long, int, const char **); +static long extract_bdm (unsigned long, int, int *); +static unsigned long insert_bdp (unsigned long, long, int, const char **); +static long extract_bdp (unsigned long, int, int *); +static unsigned long insert_bo (unsigned long, long, int, const char **); +static long extract_bo (unsigned long, int, int *); +static unsigned long insert_boe (unsigned long, long, int, const char **); +static long extract_boe (unsigned long, int, int *); +static unsigned long insert_fxm (unsigned long, long, int, const char **); +static long extract_fxm (unsigned long, int, int *); +static unsigned long insert_mbe (unsigned long, long, int, const char **); +static long extract_mbe (unsigned long, int, int *); +static unsigned long insert_mb6 (unsigned long, long, int, const char **); +static long extract_mb6 (unsigned long, int, int *); +static long extract_nb (unsigned long, int, int *); +static unsigned long insert_nsi (unsigned long, long, int, const char **); +static long extract_nsi (unsigned long, int, int *); +static unsigned long insert_ral (unsigned long, long, int, const char **); +static unsigned long insert_ram (unsigned long, long, int, const char **); +static unsigned long insert_raq (unsigned long, long, int, const char **); +static unsigned long insert_ras (unsigned long, long, int, const char **); +static unsigned long insert_rbs (unsigned long, long, int, const char **); +static long extract_rbs (unsigned long, int, int *); +static unsigned long insert_sh6 (unsigned long, long, int, const char **); +static long extract_sh6 (unsigned long, int, int *); +static unsigned long insert_spr (unsigned long, long, int, const char **); +static long extract_spr (unsigned long, int, int *); +static unsigned long insert_sprg (unsigned long, long, int, const char **); +static long extract_sprg (unsigned long, int, int *); +static unsigned long insert_tbr (unsigned long, long, int, const char **); +static long extract_tbr (unsigned long, int, int *); + +/* The operands table. + + The fields are bitm, shift, insert, extract, flags. + + We used to put parens around the various additions, like the one + for BA just below. However, that caused trouble with feeble + compilers with a limit on depth of a parenthesized expression, like + (reportedly) the compiler in Microsoft Developer Studio 5. So we + omit the parens, since the macros are never used in a context where + the addition will be ambiguous. */ + +const struct powerpc_operand powerpc_operands[] = +{ + /* The zero index is used to indicate the end of the list of + operands. */ +#define UNUSED 0 + { 0, 0, NULL, NULL, 0 }, + + /* The BA field in an XL form instruction. */ +#define BA UNUSED + 1 + /* The BI field in a B form or XL form instruction. */ +#define BI BA +#define BI_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR }, + + /* The BA field in an XL form instruction when it must be the same + as the BT field in the same instruction. */ +#define BAT BA + 1 + { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, + + /* The BB field in an XL form instruction. */ +#define BB BAT + 1 +#define BB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR }, + + /* The BB field in an XL form instruction when it must be the same + as the BA field in the same instruction. */ +#define BBA BB + 1 + { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, + + /* The BD field in a B form instruction. The lower two bits are + forced to zero. */ +#define BD BBA + 1 + { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when absolute addressing is + used. */ +#define BDA BD + 1 + { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDM BDA + 1 + { 0xfffc, 0, insert_bdm, extract_bdm, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used + and absolute address is used. */ +#define BDMA BDM + 1 + { 0xfffc, 0, insert_bdm, extract_bdm, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDP BDMA + 1 + { 0xfffc, 0, insert_bdp, extract_bdp, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used + and absolute addressing is used. */ +#define BDPA BDP + 1 + { 0xfffc, 0, insert_bdp, extract_bdp, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BF field in an X or XL form instruction. */ +#define BF BDPA + 1 + /* The CRFD field in an X form instruction. */ +#define CRFD BF + { 0x7, 23, NULL, NULL, PPC_OPERAND_CR }, + + /* The BF field in an X or XL form instruction. */ +#define BFF BF + 1 + { 0x7, 23, NULL, NULL, 0 }, + + /* An optional BF field. This is used for comparison instructions, + in which an omitted BF field is taken as zero. */ +#define OBF BFF + 1 + { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The BFA field in an X or XL form instruction. */ +#define BFA OBF + 1 + { 0x7, 18, NULL, NULL, PPC_OPERAND_CR }, + + /* The BO field in a B form instruction. Certain values are + illegal. */ +#define BO BFA + 1 +#define BO_MASK (0x1f << 21) + { 0x1f, 21, insert_bo, extract_bo, 0 }, + + /* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. */ +#define BOE BO + 1 + { 0x1e, 21, insert_boe, extract_boe, 0 }, + +#define BH BOE + 1 + { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The BT field in an X or XL form instruction. */ +#define BT BH + 1 + { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR }, + + /* The condition register number portion of the BI field in a B form + or XL form instruction. This is used for the extended + conditional branch mnemonics, which set the lower two bits of the + BI field. This field is optional. */ +#define CR BT + 1 + { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The CRB field in an X form instruction. */ +#define CRB CR + 1 + /* The MB field in an M form instruction. */ +#define MB CRB +#define MB_MASK (0x1f << 6) + { 0x1f, 6, NULL, NULL, 0 }, + + /* The CRFS field in an X form instruction. */ +#define CRFS CRB + 1 + { 0x7, 0, NULL, NULL, PPC_OPERAND_CR }, + + /* The CT field in an X form instruction. */ +#define CT CRFS + 1 + /* The MO field in an mbar instruction. */ +#define MO CT + { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The D field in a D form instruction. This is a displacement off + a register, and implies that the next operand is a register in + parentheses. */ +#define D CT + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DE field in a DE form instruction. This is like D, but is 12 + bits only. */ +#define DE D + 1 + { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DES field in a DES form instruction. This is like DS, but is 14 + bits only (12 stored.) */ +#define DES DE + 1 + { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DQ field in a DQ form instruction. This is like D, but the + lower four bits are forced to zero. */ +#define DQ DES + 1 + { 0xfff0, 0, NULL, NULL, + PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ }, + + /* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ +#undef DS +#define DS DQ + 1 + { 0xfffc, 0, NULL, NULL, + PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS }, + + /* The E field in a wrteei instruction. */ +#define E DS + 1 + { 0x1, 15, NULL, NULL, 0 }, + + /* The FL1 field in a POWER SC form instruction. */ +#define FL1 E + 1 + /* The U field in an X form instruction. */ +#define U FL1 + { 0xf, 12, NULL, NULL, 0 }, + + /* The FL2 field in a POWER SC form instruction. */ +#define FL2 FL1 + 1 + { 0x7, 2, NULL, NULL, 0 }, + + /* The FLM field in an XFL form instruction. */ +#define FLM FL2 + 1 + { 0xff, 17, NULL, NULL, 0 }, + + /* The FRA field in an X or A form instruction. */ +#define FRA FLM + 1 +#define FRA_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRB field in an X or A form instruction. */ +#define FRB FRA + 1 +#define FRB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRC field in an A form instruction. */ +#define FRC FRB + 1 +#define FRC_MASK (0x1f << 6) + { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRS field in an X form instruction or the FRT field in a D, X + or A form instruction. */ +#define FRS FRC + 1 +#define FRT FRS + { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FXM field in an XFX instruction. */ +#define FXM FRS + 1 + { 0xff, 12, insert_fxm, extract_fxm, 0 }, + + /* Power4 version for mfcr. */ +#define FXM4 FXM + 1 + { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL }, + + /* The L field in a D or X form instruction. */ +#define L FXM4 + 1 + { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The LEV field in a POWER SVC form instruction. */ +#define SVC_LEV L + 1 + { 0x7f, 5, NULL, NULL, 0 }, + + /* The LEV field in an SC form instruction. */ +#define LEV SVC_LEV + 1 + { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The LI field in an I form instruction. The lower two bits are + forced to zero. */ +#define LI LEV + 1 + { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The LI field in an I form instruction when used as an absolute + address. */ +#define LIA LI + 1 + { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The LS field in an X (sync) form instruction. */ +#define LS LIA + 1 + { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The ME field in an M form instruction. */ +#define ME LS + 1 +#define ME_MASK (0x1f << 1) + { 0x1f, 1, NULL, NULL, 0 }, + + /* The MB and ME fields in an M form instruction expressed a single + operand which is a bitmask indicating which bits to select. This + is a two operand form using PPC_OPERAND_NEXT. See the + description in opcode/ppc.h for what this means. */ +#define MBE ME + 1 + { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, + { -1, 0, insert_mbe, extract_mbe, 0 }, + + /* The MB or ME field in an MD or MDS form instruction. The high + bit is wrapped to the low end. */ +#define MB6 MBE + 2 +#define ME6 MB6 +#define MB6_MASK (0x3f << 5) + { 0x3f, 5, insert_mb6, extract_mb6, 0 }, + + /* The NB field in an X form instruction. The value 32 is stored as + 0. */ +#define NB MB6 + 1 + { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 }, + + /* The NSI field in a D form instruction. This is the same as the + SI field, only negated. */ +#define NSI NB + 1 + { 0xffff, 0, insert_nsi, extract_nsi, + PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, + + /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */ +#define RA NSI + 1 +#define RA_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR }, + + /* As above, but 0 in the RA field means zero, not r0. */ +#define RA0 RA + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in the DQ form lq instruction, which has special + value restrictions. */ +#define RAQ RA0 + 1 + { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ +#define RAL RAQ + 1 + { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in an lmw instruction, which has special value + restrictions. */ +#define RAM RAL + 1 + { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ +#define RAS RAM + 1 + { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field of the tlbwe instruction, which is optional. */ +#define RAOPT RAS + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, + + /* The RB field in an X, XO, M, or MDS form instruction. */ +#define RB RAOPT + 1 +#define RB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR }, + + /* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. */ +#define RBS RB + 1 + { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, + + /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form + instruction or the RT field in a D, DS, X, XFX or XO form + instruction. */ +#define RS RBS + 1 +#define RT RS +#define RT_MASK (0x1f << 21) + { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR }, + + /* The RS and RT fields of the DS form stq instruction, which have + special value restrictions. */ +#define RSQ RS + 1 +#define RTQ RSQ + { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 }, + + /* The RS field of the tlbwe instruction, which is optional. */ +#define RSO RSQ + 1 +#define RTO RSO + { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, + + /* The SH field in an X or M form instruction. */ +#define SH RSO + 1 +#define SH_MASK (0x1f << 11) + /* The other UIMM field in a EVX form instruction. */ +#define EVUIMM SH + { 0x1f, 11, NULL, NULL, 0 }, + + /* The SH field in an MD form instruction. This is split. */ +#define SH6 SH + 1 +#define SH6_MASK ((0x1f << 11) | (1 << 1)) + { 0x3f, -1, insert_sh6, extract_sh6, 0 }, + + /* The SH field of the tlbwe instruction, which is optional. */ +#define SHO SH6 + 1 + { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The SI field in a D form instruction. */ +#define SI SHO + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED }, + + /* The SI field in a D form instruction when we accept a wide range + of positive values. */ +#define SISIGNOPT SI + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, + + /* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ +#define SPR SISIGNOPT + 1 +#define PMR SPR +#define SPR_MASK (0x3ff << 11) + { 0x3ff, 11, insert_spr, extract_spr, 0 }, + + /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ +#define SPRBAT SPR + 1 +#define SPRBAT_MASK (0x3 << 17) + { 0x3, 17, NULL, NULL, 0 }, + + /* The SPRG register number in an XFX form m[ft]sprg instruction. */ +#define SPRG SPRBAT + 1 + { 0x1f, 16, insert_sprg, extract_sprg, 0 }, + + /* The SR field in an X form instruction. */ +#define SR SPRG + 1 + { 0xf, 16, NULL, NULL, 0 }, + + /* The STRM field in an X AltiVec form instruction. */ +#define STRM SR + 1 + { 0x3, 21, NULL, NULL, 0 }, + + /* The SV field in a POWER SC form instruction. */ +#define SV STRM + 1 + { 0x3fff, 2, NULL, NULL, 0 }, + + /* The TBR field in an XFX form instruction. This is like the SPR + field, but it is optional. */ +#define TBR SV + 1 + { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, + + /* The TO field in a D or X form instruction. */ +#define TO TBR + 1 +#define TO_MASK (0x1f << 21) + { 0x1f, 21, NULL, NULL, 0 }, + + /* The UI field in a D form instruction. */ +#define UI TO + 1 + { 0xffff, 0, NULL, NULL, 0 }, + + /* The VA field in a VA, VX or VXR form instruction. */ +#define VA UI + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR }, + + /* The VB field in a VA, VX or VXR form instruction. */ +#define VB VA + 1 + { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR }, + + /* The VC field in a VA form instruction. */ +#define VC VB + 1 + { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR }, + + /* The VD or VS field in a VA, VX, VXR or X form instruction. */ +#define VD VC + 1 +#define VS VD + { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR }, + + /* The SIMM field in a VX form instruction. */ +#define SIMM VD + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED}, + + /* The UIMM field in a VX form instruction, and TE in Z form. */ +#define UIMM SIMM + 1 +#define TE UIMM + { 0x1f, 16, NULL, NULL, 0 }, + + /* The SHB field in a VA form instruction. */ +#define SHB UIMM + 1 + { 0xf, 6, NULL, NULL, 0 }, + + /* The other UIMM field in a half word EVX form instruction. */ +#define EVUIMM_2 SHB + 1 + { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The other UIMM field in a word EVX form instruction. */ +#define EVUIMM_4 EVUIMM_2 + 1 + { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The other UIMM field in a double EVX form instruction. */ +#define EVUIMM_8 EVUIMM_4 + 1 + { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The WS field. */ +#define WS EVUIMM_8 + 1 + { 0x7, 11, NULL, NULL, 0 }, + + /* The L field in an mtmsrd or A form instruction or W in an X form. */ +#define A_L WS + 1 +#define W A_L + { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL }, + +#define RMC A_L + 1 + { 0x3, 9, NULL, NULL, 0 }, + +#define R RMC + 1 + { 0x1, 16, NULL, NULL, 0 }, + +#define SP R + 1 + { 0x3, 19, NULL, NULL, 0 }, + +#define S SP + 1 + { 0x1, 20, NULL, NULL, 0 }, + + /* SH field starting at bit position 16. */ +#define SH16 S + 1 + /* The DCM and DGM fields in a Z form instruction. */ +#define DCM SH16 +#define DGM DCM + { 0x3f, 10, NULL, NULL, 0 }, + + /* The EH field in larx instruction. */ +#define EH SH16 + 1 + { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The L field in an mtfsf or XFL form instruction. */ +#define XFL_L EH + 1 + { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL}, +}; + +const unsigned int num_powerpc_operands = (sizeof (powerpc_operands) + / sizeof (powerpc_operands[0])); + +/* The functions used to insert and extract complicated operands. */ + +/* The BA field in an XL form instruction when it must be the same as + the BT field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BT field into the BA field, + and the extraction function just checks that the fields are the + same. */ + +static unsigned long +insert_bat (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static long +extract_bat (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BB field in an XL form instruction when it must be the same as + the BA field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BA field into the BB field, + and the extraction function just checks that the fields are the + same. */ + +static unsigned long +insert_bba (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 16) & 0x1f) << 11); +} + +static long +extract_bba (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BD field in a B form instruction when the - modifier is used. + This modifier means that the branch is not expected to be taken. + For chips built to versions of the architecture prior to version 2 + (ie. not Power4 compatible), we set the y bit of the BO field to 1 + if the offset is negative. When extracting, we require that the y + bit be 1 and that the offset be positive, since if the y bit is 0 + we just want to print the normal form of the instruction. + Power4 compatible targets use two bits, "a", and "t", instead of + the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable, + "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001 + in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000 + for branch on CTR. We only handle the taken/not-taken hint here. + Note that we don't relax the conditions tested here when + disassembling with -Many because insns using extract_bdm and + extract_bdp always occur in pairs. One or the other will always + be valid. */ + +static unsigned long +insert_bdm (unsigned long insn, + long value, + int dialect, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if ((value & 0x8000) != 0) + insn |= 1 << 21; + } + else + { + if ((insn & (0x14 << 21)) == (0x04 << 21)) + insn |= 0x02 << 21; + else if ((insn & (0x14 << 21)) == (0x10 << 21)) + insn |= 0x08 << 21; + } + return insn | (value & 0xfffc); +} + +static long +extract_bdm (unsigned long insn, + int dialect, + int *invalid) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0)) + *invalid = 1; + } + else + { + if ((insn & (0x17 << 21)) != (0x06 << 21) + && (insn & (0x1d << 21)) != (0x18 << 21)) + *invalid = 1; + } + + return ((insn & 0xfffc) ^ 0x8000) - 0x8000; +} + +/* The BD field in a B form instruction when the + modifier is used. + This is like BDM, above, except that the branch is expected to be + taken. */ + +static unsigned long +insert_bdp (unsigned long insn, + long value, + int dialect, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if ((value & 0x8000) == 0) + insn |= 1 << 21; + } + else + { + if ((insn & (0x14 << 21)) == (0x04 << 21)) + insn |= 0x03 << 21; + else if ((insn & (0x14 << 21)) == (0x10 << 21)) + insn |= 0x09 << 21; + } + return insn | (value & 0xfffc); +} + +static long +extract_bdp (unsigned long insn, + int dialect, + int *invalid) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0)) + *invalid = 1; + } + else + { + if ((insn & (0x17 << 21)) != (0x07 << 21) + && (insn & (0x1d << 21)) != (0x19 << 21)) + *invalid = 1; + } + + return ((insn & 0xfffc) ^ 0x8000) - 0x8000; +} + +/* Check for legal values of a BO field. */ + +static int +valid_bo (long value, int dialect, int extract) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + int valid; + /* Certain encodings have bits that are required to be zero. + These are (z must be zero, y may be anything): + 001zy + 011zy + 1z00y + 1z01y + 1z1zz + */ + switch (value & 0x14) + { + default: + case 0: + valid = 1; + break; + case 0x4: + valid = (value & 0x2) == 0; + break; + case 0x10: + valid = (value & 0x8) == 0; + break; + case 0x14: + valid = value == 0x14; + break; + } + /* When disassembling with -Many, accept power4 encodings too. */ + if (valid + || (dialect & PPC_OPCODE_ANY) == 0 + || !extract) + return valid; + } + + /* Certain encodings have bits that are required to be zero. + These are (z must be zero, a & t may be anything): + 0000z + 0001z + 0100z + 0101z + 001at + 011at + 1a00t + 1a01t + 1z1zz + */ + if ((value & 0x14) == 0) + return (value & 0x1) == 0; + else if ((value & 0x14) == 0x14) + return value == 0x14; + else + return 1; +} + +/* The BO field in a B form instruction. Warn about attempts to set + the field to an illegal value. */ + +static unsigned long +insert_bo (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + if (!valid_bo (value, dialect, 0)) + *errmsg = _("invalid conditional option"); + return insn | ((value & 0x1f) << 21); +} + +static long +extract_bo (unsigned long insn, + int dialect, + int *invalid) +{ + long value; + + value = (insn >> 21) & 0x1f; + if (!valid_bo (value, dialect, 1)) + *invalid = 1; + return value; +} + +/* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. When + extracting it, we force it to be even. */ + +static unsigned long +insert_boe (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + if (!valid_bo (value, dialect, 0)) + *errmsg = _("invalid conditional option"); + else if ((value & 1) != 0) + *errmsg = _("attempt to set y bit when using + or - modifier"); + + return insn | ((value & 0x1f) << 21); +} + +static long +extract_boe (unsigned long insn, + int dialect, + int *invalid) +{ + long value; + + value = (insn >> 21) & 0x1f; + if (!valid_bo (value, dialect, 1)) + *invalid = 1; + return value & 0x1e; +} + +/* FXM mask in mfcr and mtcrf instructions. */ + +static unsigned long +insert_fxm (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + /* If we're handling the mfocrf and mtocrf insns ensure that exactly + one bit of the mask field is set. */ + if ((insn & (1 << 20)) != 0) + { + if (value == 0 || (value & -value) != value) + { + *errmsg = _("invalid mask field"); + value = 0; + } + } + + /* If the optional field on mfcr is missing that means we want to use + the old form of the instruction that moves the whole cr. In that + case we'll have VALUE zero. There doesn't seem to be a way to + distinguish this from the case where someone writes mfcr %r3,0. */ + else if (value == 0) + ; + + /* If only one bit of the FXM field is set, we can use the new form + of the instruction, which is faster. Unlike the Power4 branch hint + encoding, this is not backward compatible. Do not generate the + new form unless -mpower4 has been given, or -many and the two + operand form of mfcr was used. */ + else if ((value & -value) == value + && ((dialect & PPC_OPCODE_POWER4) != 0 + || ((dialect & PPC_OPCODE_ANY) != 0 + && (insn & (0x3ff << 1)) == 19 << 1))) + insn |= 1 << 20; + + /* Any other value on mfcr is an error. */ + else if ((insn & (0x3ff << 1)) == 19 << 1) + { + *errmsg = _("ignoring invalid mfcr mask"); + value = 0; + } + + return insn | ((value & 0xff) << 12); +} + +static long +extract_fxm (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + long mask = (insn >> 12) & 0xff; + + /* Is this a Power4 insn? */ + if ((insn & (1 << 20)) != 0) + { + /* Exactly one bit of MASK should be set. */ + if (mask == 0 || (mask & -mask) != mask) + *invalid = 1; + } + + /* Check that non-power4 form of mfcr has a zero MASK. */ + else if ((insn & (0x3ff << 1)) == 19 << 1) + { + if (mask != 0) + *invalid = 1; + } + + return mask; +} + +/* The MB and ME fields in an M form instruction expressed as a single + operand which is itself a bitmask. The extraction function always + marks it as invalid, since we never want to recognize an + instruction which uses a field of this type. */ + +static unsigned long +insert_mbe (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + unsigned long uval, mask; + int mb, me, mx, count, last; + + uval = value; + + if (uval == 0) + { + *errmsg = _("illegal bitmask"); + return insn; + } + + mb = 0; + me = 32; + if ((uval & 1) != 0) + last = 1; + else + last = 0; + count = 0; + + /* mb: location of last 0->1 transition */ + /* me: location of last 1->0 transition */ + /* count: # transitions */ + + for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1) + { + if ((uval & mask) && !last) + { + ++count; + mb = mx; + last = 1; + } + else if (!(uval & mask) && last) + { + ++count; + me = mx; + last = 0; + } + } + if (me == 0) + me = 32; + + if (count != 2 && (count != 0 || ! last)) + *errmsg = _("illegal bitmask"); + + return insn | (mb << 6) | ((me - 1) << 1); +} + +static long +extract_mbe (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + long ret; + int mb, me; + int i; + + *invalid = 1; + + mb = (insn >> 6) & 0x1f; + me = (insn >> 1) & 0x1f; + if (mb < me + 1) + { + ret = 0; + for (i = mb; i <= me; i++) + ret |= 1L << (31 - i); + } + else if (mb == me + 1) + ret = ~0; + else /* (mb > me + 1) */ + { + ret = ~0; + for (i = me + 1; i < mb; i++) + ret &= ~(1L << (31 - i)); + } + return ret; +} + +/* The MB or ME field in an MD or MDS form instruction. The high bit + is wrapped to the low end. */ + +static unsigned long +insert_mb6 (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 6) | (value & 0x20); +} + +static long +extract_mb6 (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 6) & 0x1f) | (insn & 0x20); +} + +/* The NB field in an X form instruction. The value 32 is stored as + 0. */ + +static long +extract_nb (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + long ret; + + ret = (insn >> 11) & 0x1f; + if (ret == 0) + ret = 32; + return ret; +} + +/* The NSI field in a D form instruction. This is the same as the SI + field, only negated. The extraction function always marks it as + invalid, since we never want to recognize an instruction which uses + a field of this type. */ + +static unsigned long +insert_nsi (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (-value & 0xffff); +} + +static long +extract_nsi (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + *invalid = 1; + return -(((insn & 0xffff) ^ 0x8000) - 0x8000); +} + +/* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ + +static unsigned long +insert_ral (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if (value == 0 + || (unsigned long) value == ((insn >> 21) & 0x1f)) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in an lmw instruction, which has special value + restrictions. */ + +static unsigned long +insert_ram (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if ((unsigned long) value >= ((insn >> 21) & 0x1f)) + *errmsg = _("index register in load range"); + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in the DQ form lq instruction, which has special + value restrictions. */ + +static unsigned long +insert_raq (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + long rtvalue = (insn & RT_MASK) >> 21; + + if (value == rtvalue) + *errmsg = _("source and target register operands must be different"); + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ + +static unsigned long +insert_ras (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if (value == 0) + *errmsg = _("invalid register operand when updating"); + return insn | ((value & 0x1f) << 16); +} + +/* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. This operand is marked FAKE. The insertion + function just copies the BT field into the BA field, and the + extraction function just checks that the fields are the same. */ + +static unsigned long +insert_rbs (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 11); +} + +static long +extract_rbs (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The SH field in an MD form instruction. This is split. */ + +static unsigned long +insert_sh6 (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); +} + +static long +extract_sh6 (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); +} + +/* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ + +static unsigned long +insert_spr (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_spr (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); +} + +/* Some dialects have 8 SPRG registers instead of the standard 4. */ + +static unsigned long +insert_sprg (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + /* This check uses PPC_OPCODE_403 because PPC405 is later defined + as a synonym. If ever a 405 specific dialect is added this + check should use that instead. */ + if (value > 7 + || (value > 3 + && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) + *errmsg = _("invalid sprg number"); + + /* If this is mfsprg4..7 then use spr 260..263 which can be read in + user mode. Anything else must use spr 272..279. */ + if (value <= 3 || (insn & 0x100) != 0) + value |= 0x10; + + return insn | ((value & 0x17) << 16); +} + +static long +extract_sprg (unsigned long insn, + int dialect, + int *invalid) +{ + unsigned long val = (insn >> 16) & 0x1f; + + /* mfsprg can use 260..263 and 272..279. mtsprg only uses spr 272..279 + If not BOOKE or 405, then both use only 272..275. */ + if (val <= 3 + || (val < 0x10 && (insn & 0x100) != 0) + || (val - 0x10 > 3 + && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) + *invalid = 1; + return val & 7; +} + +/* The TBR field in an XFX instruction. This is just like SPR, but it + is optional. When TBR is omitted, it must be inserted as 268 (the + magic number of the TB register). These functions treat 0 + (indicating an omitted optional operand) as 268. This means that + ``mftb 4,0'' is not handled correctly. This does not matter very + much, since the architecture manual does not define mftb as + accepting any values other than 268 or 269. */ + +#define TB (268) + +static unsigned long +insert_tbr (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if (value == 0) + value = TB; + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_tbr (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + long ret; + + ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); + if (ret == TB) + ret = 0; + return ret; +} + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26) +#define OP_MASK OP (0x3f) + +/* The main opcode combined with a trap code in the TO field of a D + form instruction. Used for extended mnemonics for the trap + instructions. */ +#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21)) +#define OPTO_MASK (OP_MASK | TO_MASK) + +/* The main opcode combined with a comparison size bit in the L field + of a D form or X form instruction. Used for extended mnemonics for + the comparison instructions. */ +#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21)) +#define OPL_MASK OPL (0x3f,1) + +/* An A form instruction. */ +#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1)) +#define A_MASK A (0x3f, 0x1f, 1) + +/* An A_MASK with the FRB field fixed. */ +#define AFRB_MASK (A_MASK | FRB_MASK) + +/* An A_MASK with the FRC field fixed. */ +#define AFRC_MASK (A_MASK | FRC_MASK) + +/* An A_MASK with the FRA and FRC fields fixed. */ +#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) + +/* An AFRAFRC_MASK, but with L bit clear. */ +#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16)) + +/* A B form instruction. */ +#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1)) +#define B_MASK B (0x3f, 1, 1) + +/* A B form instruction setting the BO field. */ +#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) +#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) + +/* A BBO_MASK with the y bit of the BO field removed. This permits + matching a conditional branch regardless of the setting of the y + bit. Similarly for the 'at' bits used for power4 branch hints. */ +#define Y_MASK (((unsigned long) 1) << 21) +#define AT1_MASK (((unsigned long) 3) << 21) +#define AT2_MASK (((unsigned long) 9) << 21) +#define BBOY_MASK (BBO_MASK &~ Y_MASK) +#define BBOAT_MASK (BBO_MASK &~ AT1_MASK) + +/* A B form instruction setting the BO field and the condition bits of + the BI field. */ +#define BBOCB(op, bo, cb, aa, lk) \ + (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16)) +#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) + +/* A BBOCB_MASK with the y bit of the BO field removed. */ +#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) +#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK) +#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK) + +/* A BBOYCB_MASK in which the BI field is fixed. */ +#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) +#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) + +/* An Context form instruction. */ +#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7)) +#define CTX_MASK CTX(0x3f, 0x7) + +/* An User Context form instruction. */ +#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) +#define UCTX_MASK UCTX(0x3f, 0x1f) + +/* The main opcode mask with the RA field clear. */ +#define DRA_MASK (OP_MASK | RA_MASK) + +/* A DS form instruction. */ +#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) +#define DS_MASK DSO (0x3f, 3) + +/* A DE form instruction. */ +#define DEO(op, xop) (OP (op) | ((xop) & 0xf)) +#define DE_MASK DEO (0x3e, 0xf) + +/* An EVSEL form instruction. */ +#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3) +#define EVSEL_MASK EVSEL(0x3f, 0xff) + +/* An M form instruction. */ +#define M(op, rc) (OP (op) | ((rc) & 1)) +#define M_MASK M (0x3f, 1) + +/* An M form instruction with the ME field specified. */ +#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1)) + +/* An M_MASK with the MB and ME fields fixed. */ +#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) + +/* An M_MASK with the SH and ME fields fixed. */ +#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) + +/* An MD form instruction. */ +#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1)) +#define MD_MASK MD (0x3f, 0x7, 1) + +/* An MD_MASK with the MB field fixed. */ +#define MDMB_MASK (MD_MASK | MB6_MASK) + +/* An MD_MASK with the SH field fixed. */ +#define MDSH_MASK (MD_MASK | SH6_MASK) + +/* An MDS form instruction. */ +#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1)) +#define MDS_MASK MDS (0x3f, 0xf, 1) + +/* An MDS_MASK with the MB field fixed. */ +#define MDSMB_MASK (MDS_MASK | MB6_MASK) + +/* An SC form instruction. */ +#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) +#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) + +/* An VX form instruction. */ +#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) + +/* The mask for an VX form instruction. */ +#define VX_MASK VX(0x3f, 0x7ff) + +/* An VA form instruction. */ +#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) + +/* The mask for an VA form instruction. */ +#define VXA_MASK VXA(0x3f, 0x3f) + +/* An VXR form instruction. */ +#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) + +/* The mask for a VXR form instruction. */ +#define VXR_MASK VXR(0x3f, 0x3ff, 1) + +/* An X form instruction. */ +#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) + +/* A Z form instruction. */ +#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1)) + +/* An X form instruction with the RC bit specified. */ +#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) + +/* A Z form instruction with the RC bit specified. */ +#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1)) + +/* The mask for an X form instruction. */ +#define X_MASK XRC (0x3f, 0x3ff, 1) + +/* The mask for a Z form instruction. */ +#define Z_MASK ZRC (0x3f, 0x1ff, 1) +#define Z2_MASK ZRC (0x3f, 0xff, 1) + +/* An X_MASK with the RA field fixed. */ +#define XRA_MASK (X_MASK | RA_MASK) + +/* An XRA_MASK with the W field clear. */ +#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16)) + +/* An X_MASK with the RB field fixed. */ +#define XRB_MASK (X_MASK | RB_MASK) + +/* An X_MASK with the RT field fixed. */ +#define XRT_MASK (X_MASK | RT_MASK) + +/* An XRT_MASK mask with the L bits clear. */ +#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21)) + +/* An X_MASK with the RA and RB fields fixed. */ +#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) + +/* An XRARB_MASK, but with the L bit clear. */ +#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16)) + +/* An X_MASK with the RT and RA fields fixed. */ +#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) + +/* An XRTRA_MASK, but with L bit clear. */ +#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21)) + +/* An X form instruction with the L bit specified. */ +#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21)) + +/* The mask for an X form comparison instruction. */ +#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22)) + +/* The mask for an X form comparison instruction with the L field + fixed. */ +#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21)) + +/* An X form trap instruction with the TO field specified. */ +#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21)) +#define XTO_MASK (X_MASK | TO_MASK) + +/* An X form tlb instruction with the SH field specified. */ +#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11)) +#define XTLB_MASK (X_MASK | SH_MASK) + +/* An X form sync instruction. */ +#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21)) + +/* An X form sync instruction with everything filled in except the LS field. */ +#define XSYNC_MASK (0xff9fffff) + +/* An X_MASK, but with the EH bit clear. */ +#define XEH_MASK (X_MASK & ~((unsigned long )1)) + +/* An X form AltiVec dss instruction. */ +#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25)) +#define XDSS_MASK XDSS(0x3f, 0x3ff, 1) + +/* An XFL form instruction. */ +#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1)) +#define XFL_MASK XFL (0x3f, 0x3ff, 1) + +/* An X form isel instruction. */ +#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1)) +#define XISEL_MASK XISEL(0x3f, 0x1f) + +/* An XL form instruction with the LK field set to 0. */ +#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) + +/* An XL form instruction which uses the LK field. */ +#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) + +/* The mask for an XL form instruction. */ +#define XL_MASK XLLK (0x3f, 0x3ff, 1) + +/* An XL form instruction which explicitly sets the BO field. */ +#define XLO(op, bo, xop, lk) \ + (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) +#define XLO_MASK (XL_MASK | BO_MASK) + +/* An XL form instruction which explicitly sets the y bit of the BO + field. */ +#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21)) +#define XLYLK_MASK (XL_MASK | Y_MASK) + +/* An XL form instruction which sets the BO field and the condition + bits of the BI field. */ +#define XLOCB(op, bo, cb, xop, lk) \ + (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16)) +#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) + +/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ +#define XLBB_MASK (XL_MASK | BB_MASK) +#define XLYBB_MASK (XLYLK_MASK | BB_MASK) +#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) + +/* A mask for branch instructions using the BH field. */ +#define XLBH_MASK (XL_MASK | (0x1c << 11)) + +/* An XL_MASK with the BO and BB fields fixed. */ +#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) + +/* An XL_MASK with the BO, BI and BB fields fixed. */ +#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) + +/* An XO form instruction. */ +#define XO(op, xop, oe, rc) \ + (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1)) +#define XO_MASK XO (0x3f, 0x1ff, 1, 1) + +/* An XO_MASK with the RB field fixed. */ +#define XORB_MASK (XO_MASK | RB_MASK) + +/* An XS form instruction. */ +#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1)) +#define XS_MASK XS (0x3f, 0x1ff, 1) + +/* A mask for the FXM version of an XFX form instruction. */ +#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20)) + +/* An XFX form instruction with the FXM field filled in. */ +#define XFXM(op, xop, fxm, p4) \ + (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \ + | ((unsigned long)(p4) << 20)) + +/* An XFX form instruction with the SPR field filled in. */ +#define XSPR(op, xop, spr) \ + (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6)) +#define XSPR_MASK (X_MASK | SPR_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRBAT field. */ +#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRG field. */ +#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16)) + +/* An X form instruction with everything filled in except the E field. */ +#define XE_MASK (0xffff7fff) + +/* An X form user context instruction. */ +#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) +#define XUC_MASK XUC(0x3f, 0x1f) + +/* The BO encodings used in extended conditional branch mnemonics. */ +#define BODNZF (0x0) +#define BODNZFP (0x1) +#define BODZF (0x2) +#define BODZFP (0x3) +#define BODNZT (0x8) +#define BODNZTP (0x9) +#define BODZT (0xa) +#define BODZTP (0xb) + +#define BOF (0x4) +#define BOFP (0x5) +#define BOFM4 (0x6) +#define BOFP4 (0x7) +#define BOT (0xc) +#define BOTP (0xd) +#define BOTM4 (0xe) +#define BOTP4 (0xf) + +#define BODNZ (0x10) +#define BODNZP (0x11) +#define BODZ (0x12) +#define BODZP (0x13) +#define BODNZM4 (0x18) +#define BODNZP4 (0x19) +#define BODZM4 (0x1a) +#define BODZP4 (0x1b) + +#define BOU (0x14) + +/* The BI condition bit encodings used in extended conditional branch + mnemonics. */ +#define CBLT (0) +#define CBGT (1) +#define CBEQ (2) +#define CBSO (3) + +/* The TO encodings used in extended trap mnemonics. */ +#define TOLGT (0x1) +#define TOLLT (0x2) +#define TOEQ (0x4) +#define TOLGE (0x5) +#define TOLNL (0x5) +#define TOLLE (0x6) +#define TOLNG (0x6) +#define TOGT (0x8) +#define TOGE (0xc) +#define TONL (0xc) +#define TOLT (0x10) +#define TOLE (0x14) +#define TONG (0x14) +#define TONE (0x18) +#define TOU (0x1f) + +/* Smaller names for the flags so each entry in the opcodes table will + fit on a single line. */ +#undef PPC +#define PPC PPC_OPCODE_PPC +#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON +#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM +#define POWER4 PPC_OPCODE_POWER4 +#define POWER5 PPC_OPCODE_POWER5 +#define POWER6 PPC_OPCODE_POWER6 +#define CELL PPC_OPCODE_CELL +#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC +#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC +#define PPC403 PPC_OPCODE_403 +#define PPC405 PPC403 +#define PPC440 PPC_OPCODE_440 +#define PPC750 PPC +#define PPC860 PPC +#define PPCVEC PPC_OPCODE_ALTIVEC +#define POWER PPC_OPCODE_POWER +#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2 +#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 +#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_32 +#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON +#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32 +#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601 +#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON +#define MFDEC1 PPC_OPCODE_POWER +#define MFDEC2 PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE +#define BOOKE PPC_OPCODE_BOOKE +#define BOOKE64 PPC_OPCODE_BOOKE64 +#define CLASSIC PPC_OPCODE_CLASSIC +#define PPCE300 PPC_OPCODE_E300 +#define PPCSPE PPC_OPCODE_SPE +#define PPCISEL PPC_OPCODE_ISEL +#define PPCEFS PPC_OPCODE_EFS +#define PPCBRLK PPC_OPCODE_BRLOCK +#define PPCPMR PPC_OPCODE_PMR +#define PPCCHLK PPC_OPCODE_CACHELCK +#define PPCCHLK64 PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64 +#define PPCRFMCI PPC_OPCODE_RFMCI + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK FLAGS { OPERANDS } + + NAME is the name of the instruction. + OPCODE is the instruction opcode. + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + FLAGS are flags indicated what processors support the instruction. + OPERANDS is the list of operands. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. It is also + sorted by major opcode. */ + +const struct powerpc_opcode powerpc_opcodes[] = { +{ "attn", X(0,256), X_MASK, POWER4, { 0 } }, +{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdi", OP(2), OP_MASK, PPC64, { TO, RA, SI } }, + +{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tllti", OPTO(3,TOLLT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "teqi", OPTO(3,TOEQ), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tllei", OPTO(3,TOLLE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tgti", OPTO(3,TOGT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tgei", OPTO(3,TOGE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twnli", OPTO(3,TONL), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tnli", OPTO(3,TONL), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlti", OPTO(3,TOLT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlei", OPTO(3,TOLE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twngi", OPTO(3,TONG), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tngi", OPTO(3,TONG), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twnei", OPTO(3,TONE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tnei", OPTO(3,TONE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twi", OP(3), OP_MASK, PPCCOM, { TO, RA, SI } }, +{ "ti", OP(3), OP_MASK, PWRCOM, { TO, RA, SI } }, + +{ "macchw", XO(4,172,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchw.", XO(4,172,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwo", XO(4,172,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwo.", XO(4,172,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchws", XO(4,236,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchws.", XO(4,236,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwso", XO(4,236,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwso.", XO(4,236,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsu", XO(4,204,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsu.", XO(4,204,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsuo", XO(4,204,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsuo.", XO(4,204,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwu", XO(4,140,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwu.", XO(4,140,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwuo", XO(4,140,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwuo.", XO(4,140,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhw", XO(4,44,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhw.", XO(4,44,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwo", XO(4,44,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwo.", XO(4,44,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhws", XO(4,108,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhws.", XO(4,108,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwso", XO(4,108,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwso.", XO(4,108,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsu", XO(4,76,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsu.", XO(4,76,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsuo", XO(4,76,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsuo.", XO(4,76,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwu", XO(4,12,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwu.", XO(4,12,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwuo", XO(4,12,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwuo.", XO(4,12,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhw", XO(4,428,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhw.", XO(4,428,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwo", XO(4,428,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwo.", XO(4,428,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhws", XO(4,492,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhws.", XO(4,492,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwso", XO(4,492,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwso.", XO(4,492,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsu", XO(4,460,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsu.", XO(4,460,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsuo", XO(4,460,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsuo.", XO(4,460,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwu", XO(4,396,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwu.", XO(4,396,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwuo", XO(4,396,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwuo.", XO(4,396,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchw", XRC(4,168,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchw.", XRC(4,168,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchwu", XRC(4,136,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchwu.", XRC(4,136,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhw", XRC(4,40,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhw.", XRC(4,40,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhwu", XRC(4,8,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhwu.", XRC(4,8,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhw", XRC(4,424,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhw.", XRC(4,424,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhwu", XRC(4,392,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhwu.", XRC(4,392,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchw", XO(4,174,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchw.", XO(4,174,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwo", XO(4,174,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwo.", XO(4,174,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchws", XO(4,238,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchws.", XO(4,238,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwso", XO(4,238,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwso.", XO(4,238,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhw", XO(4,46,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhw.", XO(4,46,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwo", XO(4,46,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwo.", XO(4,46,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhws", XO(4,110,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhws.", XO(4,110,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwso", XO(4,110,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwso.", XO(4,110,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhw", XO(4,430,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhw.", XO(4,430,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwo", XO(4,430,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwo.", XO(4,430,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhws", XO(4,494,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhws.", XO(4,494,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwso", XO(4,494,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwso.", XO(4,494,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mfvscr", VX(4, 1540), VX_MASK, PPCVEC, { VD } }, +{ "mtvscr", VX(4, 1604), VX_MASK, PPCVEC, { VB } }, + + /* Double-precision opcodes. */ + /* Some of these conflict with AltiVec, so move them before, since + PPCVEC includes the PPC_OPCODE_PPC set. */ +{ "efscfd", VX(4, 719), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdabs", VX(4, 740), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdnabs", VX(4, 741), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdneg", VX(4, 742), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdadd", VX(4, 736), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdsub", VX(4, 737), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdmul", VX(4, 744), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efddiv", VX(4, 745), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdcmpgt", VX(4, 748), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcmplt", VX(4, 749), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcmpeq", VX(4, 750), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtstgt", VX(4, 764), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtstlt", VX(4, 765), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtsteq", VX(4, 766), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcfsi", VX(4, 753), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfsid", VX(4, 739), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfui", VX(4, 752), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfuid", VX(4, 738), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfsf", VX(4, 755), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfuf", VX(4, 754), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsi", VX(4, 757), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsidz",VX(4, 747), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsiz", VX(4, 762), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctui", VX(4, 756), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuidz",VX(4, 746), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuiz", VX(4, 760), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsf", VX(4, 759), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuf", VX(4, 758), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfs", VX(4, 751), VX_MASK, PPCEFS, { RS, RB } }, + /* End of double-precision opcodes. */ + +{ "vaddcuw", VX(4, 384), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddfp", VX(4, 10), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddsbs", VX(4, 768), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddshs", VX(4, 832), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddsws", VX(4, 896), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddubm", VX(4, 0), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddubs", VX(4, 512), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduhm", VX(4, 64), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduhs", VX(4, 576), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduwm", VX(4, 128), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduws", VX(4, 640), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vand", VX(4, 1028), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vandc", VX(4, 1092), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsb", VX(4, 1282), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsh", VX(4, 1346), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsw", VX(4, 1410), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgub", VX(4, 1026), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavguh", VX(4, 1090), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavguw", VX(4, 1154), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcfsx", VX(4, 842), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vcfux", VX(4, 778), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vcmpbfp", VXR(4, 966, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpbfp.", VXR(4, 966, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpeqfp", VXR(4, 198, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequb", VXR(4, 6, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequb.", VXR(4, 6, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequh", VXR(4, 70, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequh.", VXR(4, 70, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequw", VXR(4, 134, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgefp", VXR(4, 454, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtfp", VXR(4, 710, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsb", VXR(4, 774, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsh", VXR(4, 838, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsw", VXR(4, 902, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtub", VXR(4, 518, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuh", VXR(4, 582, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuw", VXR(4, 646, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vctsxs", VX(4, 970), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vctuxs", VX(4, 906), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vexptefp", VX(4, 394), VX_MASK, PPCVEC, { VD, VB } }, +{ "vlogefp", VX(4, 458), VX_MASK, PPCVEC, { VD, VB } }, +{ "vmaddfp", VXA(4, 46), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, +{ "vmaxfp", VX(4, 1034), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsb", VX(4, 258), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsh", VX(4, 322), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsw", VX(4, 386), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxub", VX(4, 2), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxuh", VX(4, 66), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxuw", VX(4, 130), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmhaddshs", VXA(4, 32), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmhraddshs", VXA(4, 33), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vminfp", VX(4, 1098), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsb", VX(4, 770), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsh", VX(4, 834), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsw", VX(4, 898), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminub", VX(4, 514), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminuh", VX(4, 578), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminuw", VX(4, 642), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmladduhm", VXA(4, 34), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmrghb", VX(4, 12), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrghh", VX(4, 76), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrghw", VX(4, 140), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglb", VX(4, 268), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglh", VX(4, 332), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglw", VX(4, 396), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmsummbm", VXA(4, 37), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumshm", VXA(4, 40), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumshs", VXA(4, 41), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumubm", VXA(4, 36), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumuhm", VXA(4, 38), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumuhs", VXA(4, 39), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmulesb", VX(4, 776), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulesh", VX(4, 840), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuleub", VX(4, 520), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuleuh", VX(4, 584), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulosb", VX(4, 264), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulosh", VX(4, 328), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuloub", VX(4, 8), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulouh", VX(4, 72), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vnmsubfp", VXA(4, 47), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, +{ "vnor", VX(4, 1284), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vor", VX(4, 1156), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vperm", VXA(4, 43), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vpkpx", VX(4, 782), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkshss", VX(4, 398), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkshus", VX(4, 270), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkswss", VX(4, 462), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkswus", VX(4, 334), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuhum", VX(4, 14), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuhus", VX(4, 142), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuwum", VX(4, 78), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuwus", VX(4, 206), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrefp", VX(4, 266), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfim", VX(4, 714), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfin", VX(4, 522), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfip", VX(4, 650), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfiz", VX(4, 586), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrlb", VX(4, 4), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrlw", VX(4, 132), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrsqrtefp", VX(4, 330), VX_MASK, PPCVEC, { VD, VB } }, +{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslb", VX(4, 260), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsldoi", VXA(4, 44), VXA_MASK, PPCVEC, { VD, VA, VB, SHB } }, +{ "vslh", VX(4, 324), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslo", VX(4, 1036), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslw", VX(4, 388), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vspltb", VX(4, 524), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vsplth", VX(4, 588), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vspltisb", VX(4, 780), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltish", VX(4, 844), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltisw", VX(4, 908), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltw", VX(4, 652), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vsr", VX(4, 708), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrab", VX(4, 772), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrah", VX(4, 836), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsraw", VX(4, 900), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrb", VX(4, 516), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrh", VX(4, 580), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsro", VX(4, 1100), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrw", VX(4, 644), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubcuw", VX(4, 1408), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubfp", VX(4, 74), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubsbs", VX(4, 1792), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubshs", VX(4, 1856), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubsws", VX(4, 1920), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsububm", VX(4, 1024), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsububs", VX(4, 1536), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuhm", VX(4, 1088), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuhs", VX(4, 1600), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuwm", VX(4, 1152), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuws", VX(4, 1664), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsumsws", VX(4, 1928), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum2sws", VX(4, 1672), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4sbs", VX(4, 1800), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4shs", VX(4, 1608), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4ubs", VX(4, 1544), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vupkhpx", VX(4, 846), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupkhsb", VX(4, 526), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupkhsh", VX(4, 590), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklpx", VX(4, 974), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklsb", VX(4, 654), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklsh", VX(4, 718), VX_MASK, PPCVEC, { VD, VB } }, +{ "vxor", VX(4, 1220), VX_MASK, PPCVEC, { VD, VA, VB } }, + +{ "evaddw", VX(4, 512), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evaddiw", VX(4, 514), VX_MASK, PPCSPE, { RS, RB, UIMM } }, +{ "evsubfw", VX(4, 516), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsubw", VX(4, 516), VX_MASK, PPCSPE, { RS, RB, RA } }, +{ "evsubifw", VX(4, 518), VX_MASK, PPCSPE, { RS, UIMM, RB } }, +{ "evsubiw", VX(4, 518), VX_MASK, PPCSPE, { RS, RB, UIMM } }, +{ "evabs", VX(4, 520), VX_MASK, PPCSPE, { RS, RA } }, +{ "evneg", VX(4, 521), VX_MASK, PPCSPE, { RS, RA } }, +{ "evextsb", VX(4, 522), VX_MASK, PPCSPE, { RS, RA } }, +{ "evextsh", VX(4, 523), VX_MASK, PPCSPE, { RS, RA } }, +{ "evrndw", VX(4, 524), VX_MASK, PPCSPE, { RS, RA } }, +{ "evcntlzw", VX(4, 525), VX_MASK, PPCSPE, { RS, RA } }, +{ "evcntlsw", VX(4, 526), VX_MASK, PPCSPE, { RS, RA } }, + +{ "brinc", VX(4, 527), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evand", VX(4, 529), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evandc", VX(4, 530), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmr", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, BBA } }, +{ "evor", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evorc", VX(4, 539), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evxor", VX(4, 534), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "eveqv", VX(4, 537), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evnand", VX(4, 542), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evnot", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, BBA } }, +{ "evnor", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evrlw", VX(4, 552), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evrlwi", VX(4, 554), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evslw", VX(4, 548), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evslwi", VX(4, 550), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsrws", VX(4, 545), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsrwu", VX(4, 544), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsrwis", VX(4, 547), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsrwiu", VX(4, 546), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsplati", VX(4, 553), VX_MASK, PPCSPE, { RS, SIMM } }, +{ "evsplatfi", VX(4, 555), VX_MASK, PPCSPE, { RS, SIMM } }, +{ "evmergehi", VX(4, 556), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergelo", VX(4, 557), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergehilo",VX(4,558), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergelohi",VX(4,559), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evcmpgts", VX(4, 561), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpgtu", VX(4, 560), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmplts", VX(4, 563), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpltu", VX(4, 562), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpeq", VX(4, 564), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evsel", EVSEL(4,79),EVSEL_MASK, PPCSPE, { RS, RA, RB, CRFS } }, + +{ "evldd", VX(4, 769), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evlddx", VX(4, 768), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evldw", VX(4, 771), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evldwx", VX(4, 770), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evldh", VX(4, 773), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evldhx", VX(4, 772), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhe", VX(4, 785), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhex", VX(4, 784), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhou", VX(4, 789), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhoux", VX(4, 788), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhos", VX(4, 791), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhosx", VX(4, 790), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwwsplat",VX(4, 793), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwwsplatx",VX(4, 792), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhsplat",VX(4, 797), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhsplatx",VX(4, 796), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhesplat",VX(4, 777), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhesplatx",VX(4, 776), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhousplat",VX(4, 781), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhousplatx",VX(4, 780), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhossplat",VX(4, 783), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhossplatx",VX(4, 782), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evstdd", VX(4, 801), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstddx", VX(4, 800), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstdw", VX(4, 803), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstdwx", VX(4, 802), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstdh", VX(4, 805), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstdhx", VX(4, 804), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwwe", VX(4, 825), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwwex", VX(4, 824), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwwo", VX(4, 829), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwwox", VX(4, 828), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwhe", VX(4, 817), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwhex", VX(4, 816), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwho", VX(4, 821), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwhox", VX(4, 820), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evfsabs", VX(4, 644), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsnabs", VX(4, 645), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsneg", VX(4, 646), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsadd", VX(4, 640), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfssub", VX(4, 641), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfsmul", VX(4, 648), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfsdiv", VX(4, 649), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfscmpgt", VX(4, 652), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscmplt", VX(4, 653), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscmpeq", VX(4, 654), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststgt", VX(4, 668), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststlt", VX(4, 669), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststeq", VX(4, 670), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscfui", VX(4, 656), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctuiz", VX(4, 664), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfsi", VX(4, 657), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfuf", VX(4, 658), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfsf", VX(4, 659), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctui", VX(4, 660), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsi", VX(4, 661), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsiz", VX(4, 666), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctuf", VX(4, 662), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsf", VX(4, 663), VX_MASK, PPCSPE, { RS, RB } }, + +{ "efsabs", VX(4, 708), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsnabs", VX(4, 709), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsneg", VX(4, 710), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsadd", VX(4, 704), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efssub", VX(4, 705), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efsmul", VX(4, 712), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efsdiv", VX(4, 713), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efscmpgt", VX(4, 716), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscmplt", VX(4, 717), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscmpeq", VX(4, 718), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststgt", VX(4, 732), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststlt", VX(4, 733), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststeq", VX(4, 734), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscfui", VX(4, 720), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctuiz", VX(4, 728), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfsi", VX(4, 721), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfuf", VX(4, 722), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfsf", VX(4, 723), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctui", VX(4, 724), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsi", VX(4, 725), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsiz", VX(4, 730), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctuf", VX(4, 726), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsf", VX(4, 727), VX_MASK, PPCEFS, { RS, RB } }, + +{ "evmhossf", VX(4, 1031), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossfa", VX(4, 1063), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmf", VX(4, 1039), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfa", VX(4, 1071), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmi", VX(4, 1037), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmia", VX(4, 1069), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumi", VX(4, 1036), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumia", VX(4, 1068), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessf", VX(4, 1027), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfa", VX(4, 1059), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmf", VX(4, 1035), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfa", VX(4, 1067), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmi", VX(4, 1033), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmia", VX(4, 1065), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumi", VX(4, 1032), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumia", VX(4, 1064), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhossfaaw",VX(4, 1287), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossiaaw",VX(4, 1285), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfaaw",VX(4, 1295), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmiaaw",VX(4, 1293), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhousiaaw",VX(4, 1284), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumiaaw",VX(4, 1292), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfaaw",VX(4, 1283), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessiaaw",VX(4, 1281), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfaaw",VX(4, 1291), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmiaaw",VX(4, 1289), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheusiaaw",VX(4, 1280), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumiaaw",VX(4, 1288), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhossfanw",VX(4, 1415), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossianw",VX(4, 1413), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfanw",VX(4, 1423), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmianw",VX(4, 1421), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhousianw",VX(4, 1412), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumianw",VX(4, 1420), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfanw",VX(4, 1411), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessianw",VX(4, 1409), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfanw",VX(4, 1419), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmianw",VX(4, 1417), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheusianw",VX(4, 1408), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumianw",VX(4, 1416), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhogsmfaa",VX(4, 1327), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogsmiaa",VX(4, 1325), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogumiaa",VX(4, 1324), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmfaa",VX(4, 1323), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmiaa",VX(4, 1321), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegumiaa",VX(4, 1320), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhogsmfan",VX(4, 1455), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogsmian",VX(4, 1453), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogumian",VX(4, 1452), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmfan",VX(4, 1451), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmian",VX(4, 1449), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegumian",VX(4, 1448), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwhssf", VX(4, 1095), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhssfa", VX(4, 1127), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmf", VX(4, 1103), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmfa", VX(4, 1135), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmi", VX(4, 1101), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmia", VX(4, 1133), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhumi", VX(4, 1100), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhumia", VX(4, 1132), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlumi", VX(4, 1096), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumia", VX(4, 1128), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlssiaaw",VX(4, 1345), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlsmiaaw",VX(4, 1353), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlusiaaw",VX(4, 1344), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumiaaw",VX(4, 1352), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlssianw",VX(4, 1473), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlsmianw",VX(4, 1481), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlusianw",VX(4, 1472), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumianw",VX(4, 1480), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssf", VX(4, 1107), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwssfa", VX(4, 1139), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmf", VX(4, 1115), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfa", VX(4, 1147), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmi", VX(4, 1113), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmia", VX(4, 1145), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumi", VX(4, 1112), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumia", VX(4, 1144), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssfaa", VX(4, 1363), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfaa", VX(4, 1371), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmiaa", VX(4, 1369), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumiaa", VX(4, 1368), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssfan", VX(4, 1491), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfan", VX(4, 1499), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmian", VX(4, 1497), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumian", VX(4, 1496), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evaddssiaaw",VX(4, 1217), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddsmiaaw",VX(4, 1225), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddusiaaw",VX(4, 1216), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddumiaaw",VX(4, 1224), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evsubfssiaaw",VX(4, 1219), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfsmiaaw",VX(4, 1227), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfusiaaw",VX(4, 1218), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfumiaaw",VX(4, 1226), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evmra", VX(4, 1220), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evdivws", VX(4, 1222), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evdivwu", VX(4, 1223), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "mulli", OP(7), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "muli", OP(7), OP_MASK, PWRCOM, { RT, RA, SI } }, + +{ "subfic", OP(8), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "sfi", OP(8), OP_MASK, PWRCOM, { RT, RA, SI } }, + +{ "dozi", OP(9), OP_MASK, M601, { RT, RA, SI } }, + +{ "bce", B(9,0,0), B_MASK, BOOKE64, { BO, BI, BD } }, +{ "bcel", B(9,0,1), B_MASK, BOOKE64, { BO, BI, BD } }, +{ "bcea", B(9,1,0), B_MASK, BOOKE64, { BO, BI, BDA } }, +{ "bcela", B(9,1,1), B_MASK, BOOKE64, { BO, BI, BDA } }, + +{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } }, +{ "cmpldi", OPL(10,1), OPL_MASK, PPC64, { OBF, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PWRCOM, { BF, RA, UI } }, + +{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } }, +{ "cmpdi", OPL(11,1), OPL_MASK, PPC64, { OBF, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PWRCOM, { BF, RA, SI } }, + +{ "addic", OP(12), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "ai", OP(12), OP_MASK, PWRCOM, { RT, RA, SI } }, +{ "subic", OP(12), OP_MASK, PPCCOM, { RT, RA, NSI } }, + +{ "addic.", OP(13), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "ai.", OP(13), OP_MASK, PWRCOM, { RT, RA, SI } }, +{ "subic.", OP(13), OP_MASK, PPCCOM, { RT, RA, NSI } }, + +{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } }, +{ "lil", OP(14), DRA_MASK, PWRCOM, { RT, SI } }, +{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } }, +{ "cal", OP(14), OP_MASK, PWRCOM, { RT, D, RA0 } }, +{ "subi", OP(14), OP_MASK, PPCCOM, { RT, RA0, NSI } }, +{ "la", OP(14), OP_MASK, PPCCOM, { RT, D, RA0 } }, + +{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SISIGNOPT } }, +{ "liu", OP(15), DRA_MASK, PWRCOM, { RT, SISIGNOPT } }, +{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SISIGNOPT } }, +{ "cau", OP(15), OP_MASK, PWRCOM, { RT,RA0,SISIGNOPT } }, +{ "subis", OP(15), OP_MASK, PPCCOM, { RT, RA0, NSI } }, + +{ "bdnz-", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdnz+", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdnz", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BD } }, +{ "bdn", BBO(16,BODNZ,0,0), BBOATBI_MASK, PWRCOM, { BD } }, +{ "bdnzl-", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdnzl+", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdnzl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BD } }, +{ "bdnl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PWRCOM, { BD } }, +{ "bdnza-", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdnza+", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdnza", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDA } }, +{ "bdna", BBO(16,BODNZ,1,0), BBOATBI_MASK, PWRCOM, { BDA } }, +{ "bdnzla-", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdnzla+", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdnzla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDA } }, +{ "bdnla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PWRCOM, { BDA } }, +{ "bdz-", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdz+", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdz", BBO(16,BODZ,0,0), BBOATBI_MASK, COM, { BD } }, +{ "bdzl-", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdzl+", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdzl", BBO(16,BODZ,0,1), BBOATBI_MASK, COM, { BD } }, +{ "bdza-", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdza+", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdza", BBO(16,BODZ,1,0), BBOATBI_MASK, COM, { BDA } }, +{ "bdzla-", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdzla+", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdzla", BBO(16,BODZ,1,1), BBOATBI_MASK, COM, { BDA } }, +{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bt-", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bt+", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bt", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbt", BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "btl-", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "btl+", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "btl", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbtl", BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bta-", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bta+", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bta", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbta", BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "btla-", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "btla+", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "btla", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbtla", BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bf-", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bf+", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bf", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbf", BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bfl-", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bfl+", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bfl", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbfl", BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bfa-", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bfa+", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bfa", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbfa", BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bfla-", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bfla+", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bfla", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbfla", BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bc-", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDM } }, +{ "bc+", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDP } }, +{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } }, +{ "bcl-", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDM } }, +{ "bcl+", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDP } }, +{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } }, +{ "bca-", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDMA } }, +{ "bca+", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDPA } }, +{ "bca", B(16,1,0), B_MASK, COM, { BO, BI, BDA } }, +{ "bcla-", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDMA } }, +{ "bcla+", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDPA } }, +{ "bcla", B(16,1,1), B_MASK, COM, { BO, BI, BDA } }, + +{ "sc", SC(17,1,0), SC_MASK, PPC, { LEV } }, +{ "svc", SC(17,0,0), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, +{ "svcl", SC(17,0,1), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, +{ "svca", SC(17,1,0), SC_MASK, PWRCOM, { SV } }, +{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, + +{ "b", B(18,0,0), B_MASK, COM, { LI } }, +{ "bl", B(18,0,1), B_MASK, COM, { LI } }, +{ "ba", B(18,1,0), B_MASK, COM, { LIA } }, +{ "bla", B(18,1,1), B_MASK, COM, { LIA } }, + +{ "mcrf", XL(19,0), XLBB_MASK|(3 << 21)|(3 << 16), COM, { BF, BFA } }, + +{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM, { 0 } }, +{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM, { 0 } }, +{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlr-", XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlr+", XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlr-", XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlr+", XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlr-", XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlr-", XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlr+", XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelr-", XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelr+", XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlr-", XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlr+", XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM, { BI } }, +{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlrl-", XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlrl+", XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflr-", XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflr+", XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflrl-", XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflrl+", XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclr", XLLK(19,16,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bclrl", XLLK(19,16,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcr", XLLK(19,16,0), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bcrl", XLLK(19,16,1), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bclre", XLLK(19,17,0), XLBB_MASK, BOOKE64, { BO, BI } }, +{ "bclrel", XLLK(19,17,1), XLBB_MASK, BOOKE64, { BO, BI } }, + +{ "rfid", XL(19,18), 0xffffffff, PPC64, { 0 } }, + +{ "crnot", XL(19,33), XL_MASK, PPCCOM, { BT, BA, BBA } }, +{ "crnor", XL(19,33), XL_MASK, COM, { BT, BA, BB } }, +{ "rfmci", X(19,38), 0xffffffff, PPCRFMCI, { 0 } }, + +{ "rfi", XL(19,50), 0xffffffff, COM, { 0 } }, +{ "rfci", XL(19,51), 0xffffffff, PPC403 | BOOKE, { 0 } }, + +{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, + +{ "crandc", XL(19,129), XL_MASK, COM, { BT, BA, BB } }, + +{ "isync", XL(19,150), 0xffffffff, PPCCOM, { 0 } }, +{ "ics", XL(19,150), 0xffffffff, PWRCOM, { 0 } }, + +{ "crclr", XL(19,193), XL_MASK, PPCCOM, { BT, BAT, BBA } }, +{ "crxor", XL(19,193), XL_MASK, COM, { BT, BA, BB } }, + +{ "crnand", XL(19,225), XL_MASK, COM, { BT, BA, BB } }, + +{ "crand", XL(19,257), XL_MASK, COM, { BT, BA, BB } }, + +{ "hrfid", XL(19,274), 0xffffffff, POWER5 | CELL, { 0 } }, + +{ "crset", XL(19,289), XL_MASK, PPCCOM, { BT, BAT, BBA } }, +{ "creqv", XL(19,289), XL_MASK, COM, { BT, BA, BB } }, + +{ "doze", XL(19,402), 0xffffffff, POWER6, { 0 } }, + +{ "crorc", XL(19,417), XL_MASK, COM, { BT, BA, BB } }, + +{ "nap", XL(19,434), 0xffffffff, POWER6, { 0 } }, + +{ "crmove", XL(19,449), XL_MASK, PPCCOM, { BT, BA, BBA } }, +{ "cror", XL(19,449), XL_MASK, COM, { BT, BA, BB } }, + +{ "sleep", XL(19,466), 0xffffffff, POWER6, { 0 } }, +{ "rvwinkle", XL(19,498), 0xffffffff, POWER6, { 0 } }, + +{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } }, +{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } }, +{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctr-", XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctr+", XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctr-", XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctr+", XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctr", XLLK(19,528,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcctrl", XLLK(19,528,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcc", XLLK(19,528,0), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bccl", XLLK(19,528,1), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bcctre", XLLK(19,529,0), XLBB_MASK, BOOKE64, { BO, BI } }, +{ "bcctrel", XLLK(19,529,1), XLBB_MASK, BOOKE64, { BO, BI } }, + +{ "rlwimi", M(20,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlimi", M(20,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rlwimi.", M(20,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlimi.", M(20,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rotlwi", MME(21,31,0), MMBME_MASK, PPCCOM, { RA, RS, SH } }, +{ "clrlwi", MME(21,31,0), MSHME_MASK, PPCCOM, { RA, RS, MB } }, +{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlinm", M(21,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, +{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPCCOM, { RA,RS,SH } }, +{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPCCOM, { RA, RS, MB } }, +{ "rlwinm.", M(21,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlinm.", M(21,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rlmi", M(22,0), M_MASK, M601, { RA,RS,RB,MBE,ME } }, +{ "rlmi.", M(22,1), M_MASK, M601, { RA,RS,RB,MBE,ME } }, + +{ "be", B(22,0,0), B_MASK, BOOKE64, { LI } }, +{ "bel", B(22,0,1), B_MASK, BOOKE64, { LI } }, +{ "bea", B(22,1,0), B_MASK, BOOKE64, { LIA } }, +{ "bela", B(22,1,1), B_MASK, BOOKE64, { LIA } }, + +{ "rotlw", MME(23,31,0), MMBME_MASK, PPCCOM, { RA, RS, RB } }, +{ "rlwnm", M(23,0), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, +{ "rlnm", M(23,0), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, +{ "rotlw.", MME(23,31,1), MMBME_MASK, PPCCOM, { RA, RS, RB } }, +{ "rlwnm.", M(23,1), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, +{ "rlnm.", M(23,1), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, + +{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } }, +{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "oril", OP(24), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "oris", OP(25), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "oriu", OP(25), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "xori", OP(26), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "xoril", OP(26), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "xoriu", OP(27), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "andi.", OP(28), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "andil.", OP(28), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "andis.", OP(29), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "andiu.", OP(29), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "rotldi", MD(30,0,0), MDMB_MASK, PPC64, { RA, RS, SH6 } }, +{ "clrldi", MD(30,0,0), MDSH_MASK, PPC64, { RA, RS, MB6 } }, +{ "rldicl", MD(30,0,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC64, { RA, RS, SH6 } }, +{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC64, { RA, RS, MB6 } }, +{ "rldicl.", MD(30,0,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rldicr", MD(30,1,0), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, +{ "rldicr.", MD(30,1,1), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, + +{ "rldic", MD(30,2,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rldic.", MD(30,2,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rldimi", MD(30,3,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rldimi.", MD(30,3,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC64, { RA, RS, RB } }, +{ "rldcl", MDS(30,8,0), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, +{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC64, { RA, RS, RB } }, +{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, + +{ "rldcr", MDS(30,9,0), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, +{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, + +{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, +{ "cmpd", XOPL(31,0,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, +{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmp", X(31,0), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, + +{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tllt", XTO(31,4,TOLLT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPCCOM, { RA, RB } }, +{ "teq", XTO(31,4,TOEQ), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlge", XTO(31,4,TOLGE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlle", XTO(31,4,TOLLE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlng", XTO(31,4,TOLNG), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tgt", XTO(31,4,TOGT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twge", XTO(31,4,TOGE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tge", XTO(31,4,TOGE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twnl", XTO(31,4,TONL), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tnl", XTO(31,4,TONL), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlt", XTO(31,4,TOLT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twle", XTO(31,4,TOLE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tle", XTO(31,4,TOLE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twng", XTO(31,4,TONG), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tng", XTO(31,4,TONG), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twne", XTO(31,4,TONE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tne", XTO(31,4,TONE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "trap", XTO(31,4,TOU), 0xffffffff, PPCCOM, { 0 } }, +{ "tw", X(31,4), X_MASK, PPCCOM, { TO, RA, RB } }, +{ "t", X(31,4), X_MASK, PWRCOM, { TO, RA, RB } }, + +{ "subfc", XO(31,8,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sf", XO(31,8,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sf.", XO(31,8,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RB, RA } }, +{ "subfco", XO(31,8,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfo", XO(31,8,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco.", XO(31,8,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfo.", XO(31,8,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addc", XO(31,10,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "a", XO(31,10,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addc.", XO(31,10,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "a.", XO(31,10,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addco", XO(31,10,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ao", XO(31,10,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addco.", XO(31,10,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ao.", XO(31,10,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "isellt", X(31,15), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "iselgt", X(31,47), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "iseleq", X(31,79), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "isel", XISEL(31,15), XISEL_MASK, PPCISEL, { RT, RA, RB, CRB } }, + +{ "mfocrf", XFXM(31,19,0,1), XFXFXM_MASK, COM, { RT, FXM } }, +{ "mfcr", X(31,19), XRARB_MASK, NOPOWER4 | COM, { RT } }, +{ "mfcr", X(31,19), XFXFXM_MASK, POWER4, { RT, FXM4 } }, + +{ "lwarx", X(31,20), XEH_MASK, PPC, { RT, RA0, RB, EH } }, + +{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } }, + +{ "icbt", X(31,22), X_MASK, BOOKE|PPCE300, { CT, RA, RB } }, +{ "icbt", X(31,262), XRT_MASK, PPC403, { RA, RB } }, + +{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lx", X(31,23), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sl", XRC(31,24,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "slw.", XRC(31,24,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sl.", XRC(31,24,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "cntlzw", XRC(31,26,0), XRB_MASK, PPCCOM, { RA, RS } }, +{ "cntlz", XRC(31,26,0), XRB_MASK, PWRCOM, { RA, RS } }, +{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPCCOM, { RA, RS } }, +{ "cntlz.", XRC(31,26,1), XRB_MASK, PWRCOM, { RA, RS } }, + +{ "sld", XRC(31,27,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "sld.", XRC(31,27,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } }, +{ "and.", XRC(31,28,1), X_MASK, COM, { RA, RS, RB } }, + +{ "maskg", XRC(31,29,0), X_MASK, M601, { RA, RS, RB } }, +{ "maskg.", XRC(31,29,1), X_MASK, M601, { RA, RS, RB } }, + +{ "icbte", X(31,30), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "lwzxe", X(31,31), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, +{ "cmpld", XOPL(31,32,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, +{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmpl", X(31,32), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, + +{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "ldux", X(31,53), X_MASK, PPC64, { RT, RAL, RB } }, + +{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, + +{ "lwzux", X(31,55), X_MASK, PPCCOM, { RT, RAL, RB } }, +{ "lux", X(31,55), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dcbste", X(31,62), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lwzuxe", X(31,63), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC64, { RA, RS } }, +{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC64, { RA, RS } }, + +{ "andc", XRC(31,60,0), X_MASK, COM, { RA, RS, RB } }, +{ "andc.", XRC(31,60,1), X_MASK, COM, { RA, RS, RB } }, + +{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC64, { RA, RB } }, +{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC64, { RA, RB } }, +{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC64, { RA, RB } }, +{ "td", X(31,68), X_MASK, PPC64, { TO, RA, RB } }, + +{ "mulhd", XO(31,73,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "dlmzb", XRC(31,78,0), X_MASK, PPC403|PPC440, { RA, RS, RB } }, +{ "dlmzb.", XRC(31,78,1), X_MASK, PPC403|PPC440, { RA, RS, RB } }, + +{ "mtsrd", X(31,82), XRB_MASK|(1<<20), PPC64, { SR, RS } }, + +{ "mfmsr", X(31,83), XRARB_MASK, COM, { RT } }, + +{ "ldarx", X(31,84), XEH_MASK, PPC64, { RT, RA0, RB, EH } }, + +{ "dcbfl", XOPL(31,86,1), XRT_MASK, POWER5, { RA, RB } }, +{ "dcbf", X(31,86), XLRT_MASK, PPC, { RA, RB, L } }, + +{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } }, + +{ "dcbfe", X(31,94), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lbzxe", X(31,95), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } }, +{ "neg.", XO(31,104,0,1), XORB_MASK, COM, { RT, RA } }, +{ "nego", XO(31,104,1,0), XORB_MASK, COM, { RT, RA } }, +{ "nego.", XO(31,104,1,1), XORB_MASK, COM, { RT, RA } }, + +{ "mul", XO(31,107,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "mul.", XO(31,107,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "mulo", XO(31,107,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "mulo.", XO(31,107,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "mtsrdin", X(31,114), XRA_MASK, PPC64, { RS, RB } }, + +{ "clf", X(31,118), XTO_MASK, POWER, { RA, RB } }, + +{ "lbzux", X(31,119), X_MASK, COM, { RT, RAL, RB } }, + +{ "popcntb", X(31,122), XRB_MASK, POWER5, { RA, RS } }, + +{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } }, +{ "nor", XRC(31,124,0), X_MASK, COM, { RA, RS, RB } }, +{ "not.", XRC(31,124,1), X_MASK, COM, { RA, RS, RBS } }, +{ "nor.", XRC(31,124,1), X_MASK, COM, { RA, RS, RB } }, + +{ "lwarxe", X(31,126), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "lbzuxe", X(31,127), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "wrtee", X(31,131), XRARB_MASK, PPC403 | BOOKE, { RS } }, + +{ "dcbtstls",X(31,134), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfe", XO(31,136,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfe", XO(31,136,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfe.", XO(31,136,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfe.", XO(31,136,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfeo", XO(31,136,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfeo", XO(31,136,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfeo.", XO(31,136,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfeo.", XO(31,136,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "adde", XO(31,138,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ae", XO(31,138,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "adde.", XO(31,138,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ae.", XO(31,138,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addeo", XO(31,138,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "aeo", XO(31,138,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addeo.", XO(31,138,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "aeo.", XO(31,138,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dcbtstlse",X(31,142),X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "mtocrf", XFXM(31,144,0,1), XFXFXM_MASK, COM, { FXM, RS } }, +{ "mtcr", XFXM(31,144,0xff,0), XRARB_MASK, COM, { RS }}, +{ "mtcrf", X(31,144), XFXFXM_MASK, COM, { FXM, RS } }, + +{ "mtmsr", X(31,146), XRARB_MASK, COM, { RS } }, + +{ "stdx", X(31,149), X_MASK, PPC64, { RS, RA0, RB } }, + +{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA0, RB } }, + +{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stx", X(31,151), X_MASK, PWRCOM, { RS, RA, RB } }, + +{ "stwcxe.", XRC(31,158,1), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stwxe", X(31,159), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "slq", XRC(31,152,0), X_MASK, M601, { RA, RS, RB } }, +{ "slq.", XRC(31,152,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sle", XRC(31,153,0), X_MASK, M601, { RA, RS, RB } }, +{ "sle.", XRC(31,153,1), X_MASK, M601, { RA, RS, RB } }, + +{ "prtyw", X(31,154), XRB_MASK, POWER6, { RA, RS } }, + +{ "wrteei", X(31,163), XE_MASK, PPC403 | BOOKE, { E } }, + +{ "dcbtls", X(31,166), X_MASK, PPCCHLK, { CT, RA, RB }}, +{ "dcbtlse", X(31,174), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "mtmsrd", X(31,178), XRLARB_MASK, PPC64, { RS, A_L } }, + +{ "stdux", X(31,181), X_MASK, PPC64, { RS, RAS, RB } }, + +{ "stwux", X(31,183), X_MASK, PPCCOM, { RS, RAS, RB } }, +{ "stux", X(31,183), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "sliq", XRC(31,184,0), X_MASK, M601, { RA, RS, SH } }, +{ "sliq.", XRC(31,184,1), X_MASK, M601, { RA, RS, SH } }, + +{ "prtyd", X(31,186), XRB_MASK, POWER6, { RA, RS } }, + +{ "stwuxe", X(31,191), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "subfze", XO(31,200,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfze", XO(31,200,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfze.", XO(31,200,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfzeo", XO(31,200,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfzeo.", XO(31,200,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "addze", XO(31,202,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "aze", XO(31,202,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addze.", XO(31,202,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "aze.", XO(31,202,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addzeo", XO(31,202,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "azeo", XO(31,202,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "azeo.", XO(31,202,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mtsr", X(31,210), XRB_MASK|(1<<20), COM32, { SR, RS } }, + +{ "stdcx.", XRC(31,214,1), X_MASK, PPC64, { RS, RA0, RB } }, + +{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } }, + +{ "sllq", XRC(31,216,0), X_MASK, M601, { RA, RS, RB } }, +{ "sllq.", XRC(31,216,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sleq", XRC(31,217,0), X_MASK, M601, { RA, RS, RB } }, +{ "sleq.", XRC(31,217,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stbxe", X(31,223), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "icblc", X(31,230), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfme", XO(31,232,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfme", XO(31,232,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfme.", XO(31,232,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfmeo", XO(31,232,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfmeo.", XO(31,232,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mulld", XO(31,233,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulld.", XO(31,233,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulldo", XO(31,233,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addme", XO(31,234,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ame", XO(31,234,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addme.", XO(31,234,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ame.", XO(31,234,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addmeo", XO(31,234,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ameo", XO(31,234,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "muls.", XO(31,235,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullwo", XO(31,235,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "mulso", XO(31,235,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullwo.", XO(31,235,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "mulso.", XO(31,235,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "icblce", X(31,238), X_MASK, PPCCHLK64, { CT, RA, RB }}, +{ "mtsrin", X(31,242), XRA_MASK, PPC32, { RS, RB } }, +{ "mtsri", X(31,242), XRA_MASK, POWER32, { RS, RB } }, + +{ "dcbtst", X(31,246), X_MASK, PPC, { CT, RA, RB } }, + +{ "stbux", X(31,247), X_MASK, COM, { RS, RAS, RB } }, + +{ "slliq", XRC(31,248,0), X_MASK, M601, { RA, RS, SH } }, +{ "slliq.", XRC(31,248,1), X_MASK, M601, { RA, RS, SH } }, + +{ "dcbtste", X(31,253), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "stbuxe", X(31,255), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "mfdcrx", X(31,259), X_MASK, BOOKE, { RS, RA } }, + +{ "doz", XO(31,264,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "doz.", XO(31,264,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "dozo", XO(31,264,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "dozo.", XO(31,264,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "cax", XO(31,266,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "add.", XO(31,266,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "cax.", XO(31,266,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addo", XO(31,266,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "caxo", XO(31,266,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addo.", XO(31,266,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "caxo.", XO(31,266,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "tlbiel", X(31,274), XRTLRA_MASK, POWER4, { RB, L } }, + +{ "mfapidi", X(31,275), X_MASK, BOOKE, { RT, RA } }, + +{ "lscbx", XRC(31,277,0), X_MASK, M601, { RT, RA, RB } }, +{ "lscbx.", XRC(31,277,1), X_MASK, M601, { RT, RA, RB } }, + +{ "dcbt", X(31,278), X_MASK, PPC, { CT, RA, RB } }, + +{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } }, + +{ "eqv", XRC(31,284,0), X_MASK, COM, { RA, RS, RB } }, +{ "eqv.", XRC(31,284,1), X_MASK, COM, { RA, RS, RB } }, + +{ "dcbte", X(31,286), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "lhzxe", X(31,287), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "tlbie", X(31,306), XRTLRA_MASK, PPC, { RB, L } }, +{ "tlbi", X(31,306), XRT_MASK, POWER, { RA0, RB } }, + +{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, + +{ "lhzux", X(31,311), X_MASK, COM, { RT, RAL, RB } }, + +{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } }, +{ "xor.", XRC(31,316,1), X_MASK, COM, { RA, RS, RB } }, + +{ "lhzuxe", X(31,319), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "mfexisr", XSPR(31,323,64), XSPR_MASK, PPC403, { RT } }, +{ "mfexier", XSPR(31,323,66), XSPR_MASK, PPC403, { RT } }, +{ "mfbr0", XSPR(31,323,128), XSPR_MASK, PPC403, { RT } }, +{ "mfbr1", XSPR(31,323,129), XSPR_MASK, PPC403, { RT } }, +{ "mfbr2", XSPR(31,323,130), XSPR_MASK, PPC403, { RT } }, +{ "mfbr3", XSPR(31,323,131), XSPR_MASK, PPC403, { RT } }, +{ "mfbr4", XSPR(31,323,132), XSPR_MASK, PPC403, { RT } }, +{ "mfbr5", XSPR(31,323,133), XSPR_MASK, PPC403, { RT } }, +{ "mfbr6", XSPR(31,323,134), XSPR_MASK, PPC403, { RT } }, +{ "mfbr7", XSPR(31,323,135), XSPR_MASK, PPC403, { RT } }, +{ "mfbear", XSPR(31,323,144), XSPR_MASK, PPC403, { RT } }, +{ "mfbesr", XSPR(31,323,145), XSPR_MASK, PPC403, { RT } }, +{ "mfiocr", XSPR(31,323,160), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasr", XSPR(31,323,224), XSPR_MASK, PPC403, { RT } }, +{ "mfdcr", X(31,323), X_MASK, PPC403 | BOOKE, { RT, SPR } }, + +{ "div", XO(31,331,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "div.", XO(31,331,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "divo", XO(31,331,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divo.", XO(31,331,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "mfpmr", X(31,334), X_MASK, PPCPMR, { RT, PMR }}, + +{ "mfmq", XSPR(31,339,0), XSPR_MASK, M601, { RT } }, +{ "mfxer", XSPR(31,339,1), XSPR_MASK, COM, { RT } }, +{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, COM, { RT } }, +{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, COM, { RT } }, +{ "mfdec", XSPR(31,339,6), XSPR_MASK, MFDEC1, { RT } }, +{ "mfdec", XSPR(31,339,22), XSPR_MASK, MFDEC2, { RT } }, +{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } }, +{ "mfctr", XSPR(31,339,9), XSPR_MASK, COM, { RT } }, +{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, +{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, COM, { RT } }, +{ "mfdar", XSPR(31,339,19), XSPR_MASK, COM, { RT } }, +{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, +{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, COM, { RT } }, +{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, COM, { RT } }, +{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, COM, { RT } }, +{ "mfcfar", XSPR(31,339,28), XSPR_MASK, POWER6, { RT } }, +{ "mfpid", XSPR(31,339,48), XSPR_MASK, BOOKE, { RT } }, +{ "mfpid", XSPR(31,339,945), XSPR_MASK, PPC403, { RT } }, +{ "mfcsrr0", XSPR(31,339,58), XSPR_MASK, BOOKE, { RT } }, +{ "mfcsrr1", XSPR(31,339,59), XSPR_MASK, BOOKE, { RT } }, +{ "mfdear", XSPR(31,339,61), XSPR_MASK, BOOKE, { RT } }, +{ "mfdear", XSPR(31,339,981), XSPR_MASK, PPC403, { RT } }, +{ "mfesr", XSPR(31,339,62), XSPR_MASK, BOOKE, { RT } }, +{ "mfesr", XSPR(31,339,980), XSPR_MASK, PPC403, { RT } }, +{ "mfivpr", XSPR(31,339,63), XSPR_MASK, BOOKE, { RT } }, +{ "mfcmpa", XSPR(31,339,144), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpb", XSPR(31,339,145), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpc", XSPR(31,339,146), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpd", XSPR(31,339,147), XSPR_MASK, PPC860, { RT } }, +{ "mficr", XSPR(31,339,148), XSPR_MASK, PPC860, { RT } }, +{ "mfder", XSPR(31,339,149), XSPR_MASK, PPC860, { RT } }, +{ "mfcounta", XSPR(31,339,150), XSPR_MASK, PPC860, { RT } }, +{ "mfcountb", XSPR(31,339,151), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpe", XSPR(31,339,152), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpf", XSPR(31,339,153), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpg", XSPR(31,339,154), XSPR_MASK, PPC860, { RT } }, +{ "mfcmph", XSPR(31,339,155), XSPR_MASK, PPC860, { RT } }, +{ "mflctrl1", XSPR(31,339,156), XSPR_MASK, PPC860, { RT } }, +{ "mflctrl2", XSPR(31,339,157), XSPR_MASK, PPC860, { RT } }, +{ "mfictrl", XSPR(31,339,158), XSPR_MASK, PPC860, { RT } }, +{ "mfbar", XSPR(31,339,159), XSPR_MASK, PPC860, { RT } }, +{ "mfvrsave", XSPR(31,339,256), XSPR_MASK, PPCVEC, { RT } }, +{ "mfusprg0", XSPR(31,339,256), XSPR_MASK, BOOKE, { RT } }, +{ "mftb", X(31,371), X_MASK, CLASSIC, { RT, TBR } }, +{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, +{ "mftbl", XSPR(31,371,268), XSPR_MASK, CLASSIC, { RT } }, +{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, +{ "mftbu", XSPR(31,371,269), XSPR_MASK, CLASSIC, { RT } }, +{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } }, +{ "mfsprg", XSPR(31,339,256), XSPRG_MASK, PPC, { RT, SPRG } }, +{ "mfsprg0", XSPR(31,339,272), XSPR_MASK, PPC, { RT } }, +{ "mfsprg1", XSPR(31,339,273), XSPR_MASK, PPC, { RT } }, +{ "mfsprg2", XSPR(31,339,274), XSPR_MASK, PPC, { RT } }, +{ "mfsprg3", XSPR(31,339,275), XSPR_MASK, PPC, { RT } }, +{ "mfsprg4", XSPR(31,339,260), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg5", XSPR(31,339,261), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg6", XSPR(31,339,262), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg7", XSPR(31,339,263), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC64, { RT } }, +{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, +{ "mfpir", XSPR(31,339,286), XSPR_MASK, BOOKE, { RT } }, +{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, +{ "mfdbsr", XSPR(31,339,304), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbsr", XSPR(31,339,1008), XSPR_MASK, PPC403, { RT } }, +{ "mfdbcr0", XSPR(31,339,308), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbcr0", XSPR(31,339,1010), XSPR_MASK, PPC405, { RT } }, +{ "mfdbcr1", XSPR(31,339,309), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbcr1", XSPR(31,339,957), XSPR_MASK, PPC405, { RT } }, +{ "mfdbcr2", XSPR(31,339,310), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac1", XSPR(31,339,312), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac1", XSPR(31,339,1012), XSPR_MASK, PPC403, { RT } }, +{ "mfiac2", XSPR(31,339,313), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac2", XSPR(31,339,1013), XSPR_MASK, PPC403, { RT } }, +{ "mfiac3", XSPR(31,339,314), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac3", XSPR(31,339,948), XSPR_MASK, PPC405, { RT } }, +{ "mfiac4", XSPR(31,339,315), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac4", XSPR(31,339,949), XSPR_MASK, PPC405, { RT } }, +{ "mfdac1", XSPR(31,339,316), XSPR_MASK, BOOKE, { RT } }, +{ "mfdac1", XSPR(31,339,1014), XSPR_MASK, PPC403, { RT } }, +{ "mfdac2", XSPR(31,339,317), XSPR_MASK, BOOKE, { RT } }, +{ "mfdac2", XSPR(31,339,1015), XSPR_MASK, PPC403, { RT } }, +{ "mfdvc1", XSPR(31,339,318), XSPR_MASK, BOOKE, { RT } }, +{ "mfdvc1", XSPR(31,339,950), XSPR_MASK, PPC405, { RT } }, +{ "mfdvc2", XSPR(31,339,319), XSPR_MASK, BOOKE, { RT } }, +{ "mfdvc2", XSPR(31,339,951), XSPR_MASK, PPC405, { RT } }, +{ "mftsr", XSPR(31,339,336), XSPR_MASK, BOOKE, { RT } }, +{ "mftsr", XSPR(31,339,984), XSPR_MASK, PPC403, { RT } }, +{ "mftcr", XSPR(31,339,340), XSPR_MASK, BOOKE, { RT } }, +{ "mftcr", XSPR(31,339,986), XSPR_MASK, PPC403, { RT } }, +{ "mfivor0", XSPR(31,339,400), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor1", XSPR(31,339,401), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor2", XSPR(31,339,402), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor3", XSPR(31,339,403), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor4", XSPR(31,339,404), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor5", XSPR(31,339,405), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor6", XSPR(31,339,406), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor7", XSPR(31,339,407), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor8", XSPR(31,339,408), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor9", XSPR(31,339,409), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor10", XSPR(31,339,410), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor11", XSPR(31,339,411), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor12", XSPR(31,339,412), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor13", XSPR(31,339,413), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor14", XSPR(31,339,414), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor15", XSPR(31,339,415), XSPR_MASK, BOOKE, { RT } }, +{ "mfspefscr", XSPR(31,339,512), XSPR_MASK, PPCSPE, { RT } }, +{ "mfbbear", XSPR(31,339,513), XSPR_MASK, PPCBRLK, { RT } }, +{ "mfbbtar", XSPR(31,339,514), XSPR_MASK, PPCBRLK, { RT } }, +{ "mfivor32", XSPR(31,339,528), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor33", XSPR(31,339,529), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor34", XSPR(31,339,530), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor35", XSPR(31,339,531), XSPR_MASK, PPCPMR, { RT } }, +{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfic_cst", XSPR(31,339,560), XSPR_MASK, PPC860, { RT } }, +{ "mfic_adr", XSPR(31,339,561), XSPR_MASK, PPC860, { RT } }, +{ "mfic_dat", XSPR(31,339,562), XSPR_MASK, PPC860, { RT } }, +{ "mfdc_cst", XSPR(31,339,568), XSPR_MASK, PPC860, { RT } }, +{ "mfdc_adr", XSPR(31,339,569), XSPR_MASK, PPC860, { RT } }, +{ "mfmcsrr0", XSPR(31,339,570), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfdc_dat", XSPR(31,339,570), XSPR_MASK, PPC860, { RT } }, +{ "mfmcsrr1", XSPR(31,339,571), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfmcsr", XSPR(31,339,572), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfmcar", XSPR(31,339,573), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfdpdr", XSPR(31,339,630), XSPR_MASK, PPC860, { RT } }, +{ "mfdpir", XSPR(31,339,631), XSPR_MASK, PPC860, { RT } }, +{ "mfimmr", XSPR(31,339,638), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_ctr", XSPR(31,339,784), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_ap", XSPR(31,339,786), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_epn", XSPR(31,339,787), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_twc", XSPR(31,339,789), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_rpn", XSPR(31,339,790), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_ctr", XSPR(31,339,792), XSPR_MASK, PPC860, { RT } }, +{ "mfm_casid", XSPR(31,339,793), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_ap", XSPR(31,339,794), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_epn", XSPR(31,339,795), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_twb", XSPR(31,339,796), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_twc", XSPR(31,339,797), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_rpn", XSPR(31,339,798), XSPR_MASK, PPC860, { RT } }, +{ "mfm_tw", XSPR(31,339,799), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbcam", XSPR(31,339,816), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbram0",XSPR(31,339,817), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbram1",XSPR(31,339,818), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbcam", XSPR(31,339,824), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbram0",XSPR(31,339,825), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbram1",XSPR(31,339,826), XSPR_MASK, PPC860, { RT } }, +{ "mfummcr0", XSPR(31,339,936), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc1", XSPR(31,339,937), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc2", XSPR(31,339,938), XSPR_MASK, PPC750, { RT } }, +{ "mfusia", XSPR(31,339,939), XSPR_MASK, PPC750, { RT } }, +{ "mfummcr1", XSPR(31,339,940), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc3", XSPR(31,339,941), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc4", XSPR(31,339,942), XSPR_MASK, PPC750, { RT } }, +{ "mfzpr", XSPR(31,339,944), XSPR_MASK, PPC403, { RT } }, +{ "mfccr0", XSPR(31,339,947), XSPR_MASK, PPC405, { RT } }, +{ "mfmmcr0", XSPR(31,339,952), XSPR_MASK, PPC750, { RT } }, +{ "mfpmc1", XSPR(31,339,953), XSPR_MASK, PPC750, { RT } }, +{ "mfsgr", XSPR(31,339,953), XSPR_MASK, PPC403, { RT } }, +{ "mfpmc2", XSPR(31,339,954), XSPR_MASK, PPC750, { RT } }, +{ "mfdcwr", XSPR(31,339,954), XSPR_MASK, PPC403, { RT } }, +{ "mfsia", XSPR(31,339,955), XSPR_MASK, PPC750, { RT } }, +{ "mfsler", XSPR(31,339,955), XSPR_MASK, PPC405, { RT } }, +{ "mfmmcr1", XSPR(31,339,956), XSPR_MASK, PPC750, { RT } }, +{ "mfsu0r", XSPR(31,339,956), XSPR_MASK, PPC405, { RT } }, +{ "mfpmc3", XSPR(31,339,957), XSPR_MASK, PPC750, { RT } }, +{ "mfpmc4", XSPR(31,339,958), XSPR_MASK, PPC750, { RT } }, +{ "mficdbdr", XSPR(31,339,979), XSPR_MASK, PPC403, { RT } }, +{ "mfevpr", XSPR(31,339,982), XSPR_MASK, PPC403, { RT } }, +{ "mfcdbcr", XSPR(31,339,983), XSPR_MASK, PPC403, { RT } }, +{ "mfpit", XSPR(31,339,987), XSPR_MASK, PPC403, { RT } }, +{ "mftbhi", XSPR(31,339,988), XSPR_MASK, PPC403, { RT } }, +{ "mftblo", XSPR(31,339,989), XSPR_MASK, PPC403, { RT } }, +{ "mfsrr2", XSPR(31,339,990), XSPR_MASK, PPC403, { RT } }, +{ "mfsrr3", XSPR(31,339,991), XSPR_MASK, PPC403, { RT } }, +{ "mfl2cr", XSPR(31,339,1017), XSPR_MASK, PPC750, { RT } }, +{ "mfdccr", XSPR(31,339,1018), XSPR_MASK, PPC403, { RT } }, +{ "mficcr", XSPR(31,339,1019), XSPR_MASK, PPC403, { RT } }, +{ "mfictc", XSPR(31,339,1019), XSPR_MASK, PPC750, { RT } }, +{ "mfpbl1", XSPR(31,339,1020), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm1", XSPR(31,339,1020), XSPR_MASK, PPC750, { RT } }, +{ "mfpbu1", XSPR(31,339,1021), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm2", XSPR(31,339,1021), XSPR_MASK, PPC750, { RT } }, +{ "mfpbl2", XSPR(31,339,1022), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm3", XSPR(31,339,1022), XSPR_MASK, PPC750, { RT } }, +{ "mfpbu2", XSPR(31,339,1023), XSPR_MASK, PPC403, { RT } }, +{ "mfspr", X(31,339), X_MASK, COM, { RT, SPR } }, + +{ "lwax", X(31,341), X_MASK, PPC64, { RT, RA0, RB } }, + +{ "dst", XDSS(31,342,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, +{ "dstt", XDSS(31,342,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, + +{ "lhax", X(31,343), X_MASK, COM, { RT, RA0, RB } }, + +{ "lhaxe", X(31,351), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "dstst", XDSS(31,374,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, +{ "dststt", XDSS(31,374,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, + +{ "dccci", X(31,454), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "abs", XO(31,360,0,0), XORB_MASK, M601, { RT, RA } }, +{ "abs.", XO(31,360,0,1), XORB_MASK, M601, { RT, RA } }, +{ "abso", XO(31,360,1,0), XORB_MASK, M601, { RT, RA } }, +{ "abso.", XO(31,360,1,1), XORB_MASK, M601, { RT, RA } }, + +{ "divs", XO(31,363,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divs.", XO(31,363,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "divso", XO(31,363,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divso.", XO(31,363,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, + +{ "lwaux", X(31,373), X_MASK, PPC64, { RT, RAL, RB } }, + +{ "lhaux", X(31,375), X_MASK, COM, { RT, RAL, RB } }, + +{ "lhauxe", X(31,383), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "mtdcrx", X(31,387), X_MASK, BOOKE, { RA, RS } }, + +{ "dcblc", X(31,390), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfe64", XO(31,392,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, +{ "subfe64o",XO(31,392,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, + +{ "adde64", XO(31,394,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, +{ "adde64o", XO(31,394,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, + +{ "dcblce", X(31,398), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "slbmte", X(31,402), XRA_MASK, PPC64, { RS, RB } }, + +{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } }, + +{ "cmpb", X(31,508), X_MASK, POWER6, { RA, RS, RB } }, + +{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "lfdpx", X(31,791), X_MASK, POWER6, { FRT, RA, RB } }, + +{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "stfdpx", X(31,919), X_MASK, POWER6, { FRS, RA, RB } }, + +{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "orc", XRC(31,412,0), X_MASK, COM, { RA, RS, RB } }, +{ "orc.", XRC(31,412,1), X_MASK, COM, { RA, RS, RB } }, + +{ "sradi", XS(31,413,0), XS_MASK, PPC64, { RA, RS, SH6 } }, +{ "sradi.", XS(31,413,1), XS_MASK, PPC64, { RA, RS, SH6 } }, + +{ "sthxe", X(31,415), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "slbie", X(31,434), XRTRA_MASK, PPC64, { RB } }, + +{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, + +{ "sthux", X(31,439), X_MASK, COM, { RS, RAS, RB } }, + +{ "sthuxe", X(31,447), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "cctpl", 0x7c210b78, 0xffffffff, CELL, { 0 }}, +{ "cctpm", 0x7c421378, 0xffffffff, CELL, { 0 }}, +{ "cctph", 0x7c631b78, 0xffffffff, CELL, { 0 }}, +{ "db8cyc", 0x7f9ce378, 0xffffffff, CELL, { 0 }}, +{ "db10cyc", 0x7fbdeb78, 0xffffffff, CELL, { 0 }}, +{ "db12cyc", 0x7fdef378, 0xffffffff, CELL, { 0 }}, +{ "db16cyc", 0x7ffffb78, 0xffffffff, CELL, { 0 }}, +{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } }, +{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } }, +{ "mr.", XRC(31,444,1), X_MASK, COM, { RA, RS, RBS } }, +{ "or.", XRC(31,444,1), X_MASK, COM, { RA, RS, RB } }, + +{ "mtexisr", XSPR(31,451,64), XSPR_MASK, PPC403, { RS } }, +{ "mtexier", XSPR(31,451,66), XSPR_MASK, PPC403, { RS } }, +{ "mtbr0", XSPR(31,451,128), XSPR_MASK, PPC403, { RS } }, +{ "mtbr1", XSPR(31,451,129), XSPR_MASK, PPC403, { RS } }, +{ "mtbr2", XSPR(31,451,130), XSPR_MASK, PPC403, { RS } }, +{ "mtbr3", XSPR(31,451,131), XSPR_MASK, PPC403, { RS } }, +{ "mtbr4", XSPR(31,451,132), XSPR_MASK, PPC403, { RS } }, +{ "mtbr5", XSPR(31,451,133), XSPR_MASK, PPC403, { RS } }, +{ "mtbr6", XSPR(31,451,134), XSPR_MASK, PPC403, { RS } }, +{ "mtbr7", XSPR(31,451,135), XSPR_MASK, PPC403, { RS } }, +{ "mtbear", XSPR(31,451,144), XSPR_MASK, PPC403, { RS } }, +{ "mtbesr", XSPR(31,451,145), XSPR_MASK, PPC403, { RS } }, +{ "mtiocr", XSPR(31,451,160), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasr", XSPR(31,451,224), XSPR_MASK, PPC403, { RS } }, +{ "mtdcr", X(31,451), X_MASK, PPC403 | BOOKE, { SPR, RS } }, + +{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divdu", XO(31,457,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdu.", XO(31,457,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divduo", XO(31,457,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divduo.", XO(31,457,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mtmq", XSPR(31,467,0), XSPR_MASK, M601, { RS } }, +{ "mtxer", XSPR(31,467,1), XSPR_MASK, COM, { RS } }, +{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } }, +{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } }, +{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, +{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, COM, { RS } }, +{ "mtdar", XSPR(31,467,19), XSPR_MASK, COM, { RS } }, +{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, COM, { RS } }, +{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, COM, { RS } }, +{ "mtdec", XSPR(31,467,22), XSPR_MASK, COM, { RS } }, +{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, +{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, COM, { RS } }, +{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, COM, { RS } }, +{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, COM, { RS } }, +{ "mtcfar", XSPR(31,467,28), XSPR_MASK, POWER6, { RS } }, +{ "mtpid", XSPR(31,467,48), XSPR_MASK, BOOKE, { RS } }, +{ "mtpid", XSPR(31,467,945), XSPR_MASK, PPC403, { RS } }, +{ "mtdecar", XSPR(31,467,54), XSPR_MASK, BOOKE, { RS } }, +{ "mtcsrr0", XSPR(31,467,58), XSPR_MASK, BOOKE, { RS } }, +{ "mtcsrr1", XSPR(31,467,59), XSPR_MASK, BOOKE, { RS } }, +{ "mtdear", XSPR(31,467,61), XSPR_MASK, BOOKE, { RS } }, +{ "mtdear", XSPR(31,467,981), XSPR_MASK, PPC403, { RS } }, +{ "mtesr", XSPR(31,467,62), XSPR_MASK, BOOKE, { RS } }, +{ "mtesr", XSPR(31,467,980), XSPR_MASK, PPC403, { RS } }, +{ "mtivpr", XSPR(31,467,63), XSPR_MASK, BOOKE, { RS } }, +{ "mtcmpa", XSPR(31,467,144), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpb", XSPR(31,467,145), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpc", XSPR(31,467,146), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpd", XSPR(31,467,147), XSPR_MASK, PPC860, { RS } }, +{ "mticr", XSPR(31,467,148), XSPR_MASK, PPC860, { RS } }, +{ "mtder", XSPR(31,467,149), XSPR_MASK, PPC860, { RS } }, +{ "mtcounta", XSPR(31,467,150), XSPR_MASK, PPC860, { RS } }, +{ "mtcountb", XSPR(31,467,151), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpe", XSPR(31,467,152), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpf", XSPR(31,467,153), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpg", XSPR(31,467,154), XSPR_MASK, PPC860, { RS } }, +{ "mtcmph", XSPR(31,467,155), XSPR_MASK, PPC860, { RS } }, +{ "mtlctrl1", XSPR(31,467,156), XSPR_MASK, PPC860, { RS } }, +{ "mtlctrl2", XSPR(31,467,157), XSPR_MASK, PPC860, { RS } }, +{ "mtictrl", XSPR(31,467,158), XSPR_MASK, PPC860, { RS } }, +{ "mtbar", XSPR(31,467,159), XSPR_MASK, PPC860, { RS } }, +{ "mtvrsave", XSPR(31,467,256), XSPR_MASK, PPCVEC, { RS } }, +{ "mtusprg0", XSPR(31,467,256), XSPR_MASK, BOOKE, { RS } }, +{ "mtsprg", XSPR(31,467,256), XSPRG_MASK,PPC, { SPRG, RS } }, +{ "mtsprg0", XSPR(31,467,272), XSPR_MASK, PPC, { RS } }, +{ "mtsprg1", XSPR(31,467,273), XSPR_MASK, PPC, { RS } }, +{ "mtsprg2", XSPR(31,467,274), XSPR_MASK, PPC, { RS } }, +{ "mtsprg3", XSPR(31,467,275), XSPR_MASK, PPC, { RS } }, +{ "mtsprg4", XSPR(31,467,276), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg5", XSPR(31,467,277), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg6", XSPR(31,467,278), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg7", XSPR(31,467,279), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC64, { RS } }, +{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, +{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, +{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, +{ "mtdbsr", XSPR(31,467,304), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbsr", XSPR(31,467,1008), XSPR_MASK, PPC403, { RS } }, +{ "mtdbcr0", XSPR(31,467,308), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbcr0", XSPR(31,467,1010), XSPR_MASK, PPC405, { RS } }, +{ "mtdbcr1", XSPR(31,467,309), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbcr1", XSPR(31,467,957), XSPR_MASK, PPC405, { RS } }, +{ "mtdbcr2", XSPR(31,467,310), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac1", XSPR(31,467,312), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac1", XSPR(31,467,1012), XSPR_MASK, PPC403, { RS } }, +{ "mtiac2", XSPR(31,467,313), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac2", XSPR(31,467,1013), XSPR_MASK, PPC403, { RS } }, +{ "mtiac3", XSPR(31,467,314), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac3", XSPR(31,467,948), XSPR_MASK, PPC405, { RS } }, +{ "mtiac4", XSPR(31,467,315), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac4", XSPR(31,467,949), XSPR_MASK, PPC405, { RS } }, +{ "mtdac1", XSPR(31,467,316), XSPR_MASK, BOOKE, { RS } }, +{ "mtdac1", XSPR(31,467,1014), XSPR_MASK, PPC403, { RS } }, +{ "mtdac2", XSPR(31,467,317), XSPR_MASK, BOOKE, { RS } }, +{ "mtdac2", XSPR(31,467,1015), XSPR_MASK, PPC403, { RS } }, +{ "mtdvc1", XSPR(31,467,318), XSPR_MASK, BOOKE, { RS } }, +{ "mtdvc1", XSPR(31,467,950), XSPR_MASK, PPC405, { RS } }, +{ "mtdvc2", XSPR(31,467,319), XSPR_MASK, BOOKE, { RS } }, +{ "mtdvc2", XSPR(31,467,951), XSPR_MASK, PPC405, { RS } }, +{ "mttsr", XSPR(31,467,336), XSPR_MASK, BOOKE, { RS } }, +{ "mttsr", XSPR(31,467,984), XSPR_MASK, PPC403, { RS } }, +{ "mttcr", XSPR(31,467,340), XSPR_MASK, BOOKE, { RS } }, +{ "mttcr", XSPR(31,467,986), XSPR_MASK, PPC403, { RS } }, +{ "mtivor0", XSPR(31,467,400), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor1", XSPR(31,467,401), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor2", XSPR(31,467,402), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor3", XSPR(31,467,403), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor4", XSPR(31,467,404), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor5", XSPR(31,467,405), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor6", XSPR(31,467,406), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor7", XSPR(31,467,407), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor8", XSPR(31,467,408), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor9", XSPR(31,467,409), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor10", XSPR(31,467,410), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor11", XSPR(31,467,411), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor12", XSPR(31,467,412), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor13", XSPR(31,467,413), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor14", XSPR(31,467,414), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor15", XSPR(31,467,415), XSPR_MASK, BOOKE, { RS } }, +{ "mtspefscr", XSPR(31,467,512), XSPR_MASK, PPCSPE, { RS } }, +{ "mtbbear", XSPR(31,467,513), XSPR_MASK, PPCBRLK, { RS } }, +{ "mtbbtar", XSPR(31,467,514), XSPR_MASK, PPCBRLK, { RS } }, +{ "mtivor32", XSPR(31,467,528), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor33", XSPR(31,467,529), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor34", XSPR(31,467,530), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor35", XSPR(31,467,531), XSPR_MASK, PPCPMR, { RS } }, +{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtmcsrr0", XSPR(31,467,570), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtmcsrr1", XSPR(31,467,571), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtmcsr", XSPR(31,467,572), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtummcr0", XSPR(31,467,936), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc1", XSPR(31,467,937), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc2", XSPR(31,467,938), XSPR_MASK, PPC750, { RS } }, +{ "mtusia", XSPR(31,467,939), XSPR_MASK, PPC750, { RS } }, +{ "mtummcr1", XSPR(31,467,940), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc3", XSPR(31,467,941), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc4", XSPR(31,467,942), XSPR_MASK, PPC750, { RS } }, +{ "mtzpr", XSPR(31,467,944), XSPR_MASK, PPC403, { RS } }, +{ "mtccr0", XSPR(31,467,947), XSPR_MASK, PPC405, { RS } }, +{ "mtmmcr0", XSPR(31,467,952), XSPR_MASK, PPC750, { RS } }, +{ "mtsgr", XSPR(31,467,953), XSPR_MASK, PPC403, { RS } }, +{ "mtpmc1", XSPR(31,467,953), XSPR_MASK, PPC750, { RS } }, +{ "mtdcwr", XSPR(31,467,954), XSPR_MASK, PPC403, { RS } }, +{ "mtpmc2", XSPR(31,467,954), XSPR_MASK, PPC750, { RS } }, +{ "mtsler", XSPR(31,467,955), XSPR_MASK, PPC405, { RS } }, +{ "mtsia", XSPR(31,467,955), XSPR_MASK, PPC750, { RS } }, +{ "mtsu0r", XSPR(31,467,956), XSPR_MASK, PPC405, { RS } }, +{ "mtmmcr1", XSPR(31,467,956), XSPR_MASK, PPC750, { RS } }, +{ "mtpmc3", XSPR(31,467,957), XSPR_MASK, PPC750, { RS } }, +{ "mtpmc4", XSPR(31,467,958), XSPR_MASK, PPC750, { RS } }, +{ "mticdbdr", XSPR(31,467,979), XSPR_MASK, PPC403, { RS } }, +{ "mtevpr", XSPR(31,467,982), XSPR_MASK, PPC403, { RS } }, +{ "mtcdbcr", XSPR(31,467,983), XSPR_MASK, PPC403, { RS } }, +{ "mtpit", XSPR(31,467,987), XSPR_MASK, PPC403, { RS } }, +{ "mttbhi", XSPR(31,467,988), XSPR_MASK, PPC403, { RS } }, +{ "mttblo", XSPR(31,467,989), XSPR_MASK, PPC403, { RS } }, +{ "mtsrr2", XSPR(31,467,990), XSPR_MASK, PPC403, { RS } }, +{ "mtsrr3", XSPR(31,467,991), XSPR_MASK, PPC403, { RS } }, +{ "mtl2cr", XSPR(31,467,1017), XSPR_MASK, PPC750, { RS } }, +{ "mtdccr", XSPR(31,467,1018), XSPR_MASK, PPC403, { RS } }, +{ "mticcr", XSPR(31,467,1019), XSPR_MASK, PPC403, { RS } }, +{ "mtictc", XSPR(31,467,1019), XSPR_MASK, PPC750, { RS } }, +{ "mtpbl1", XSPR(31,467,1020), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm1", XSPR(31,467,1020), XSPR_MASK, PPC750, { RS } }, +{ "mtpbu1", XSPR(31,467,1021), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm2", XSPR(31,467,1021), XSPR_MASK, PPC750, { RS } }, +{ "mtpbl2", XSPR(31,467,1022), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm3", XSPR(31,467,1022), XSPR_MASK, PPC750, { RS } }, +{ "mtpbu2", XSPR(31,467,1023), XSPR_MASK, PPC403, { RS } }, +{ "mtspr", X(31,467), X_MASK, COM, { SPR, RS } }, + +{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, + +{ "nand", XRC(31,476,0), X_MASK, COM, { RA, RS, RB } }, +{ "nand.", XRC(31,476,1), X_MASK, COM, { RA, RS, RB } }, + +{ "dcbie", X(31,478), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "dcread", X(31,486), X_MASK, PPC403|PPC440, { RT, RA, RB }}, + +{ "mtpmr", X(31,462), X_MASK, PPCPMR, { PMR, RS }}, + +{ "icbtls", X(31,486), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "nabs", XO(31,488,0,0), XORB_MASK, M601, { RT, RA } }, +{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "nabs.", XO(31,488,0,1), XORB_MASK, M601, { RT, RA } }, +{ "nabso", XO(31,488,1,0), XORB_MASK, M601, { RT, RA } }, +{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "nabso.", XO(31,488,1,1), XORB_MASK, M601, { RT, RA } }, + +{ "divd", XO(31,489,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divd.", XO(31,489,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdo", XO(31,489,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdo.", XO(31,489,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "icbtlse", X(31,494), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "slbia", X(31,498), 0xffffffff, PPC64, { 0 } }, + +{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, + +{ "stdcxe.", XRC(31,511,1), X_MASK, BOOKE64, { RS, RA, RB } }, + +{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), COM, { BF } }, + +{ "bblels", X(31,518), X_MASK, PPCBRLK, { 0 }}, +{ "mcrxr64", X(31,544), XRARB_MASK|(3<<21), BOOKE64, { BF } }, + +{ "clcs", X(31,531), XRB_MASK, M601, { RT, RA } }, + +{ "ldbrx", X(31,532), X_MASK, CELL, { RT, RA0, RB } }, + +{ "lswx", X(31,533), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lsx", X(31,533), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lwbrx", X(31,534), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lbrx", X(31,534), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } }, + +{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sr", XRC(31,536,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "srw.", XRC(31,536,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sr.", XRC(31,536,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "rrib", XRC(31,537,0), X_MASK, M601, { RA, RS, RB } }, +{ "rrib.", XRC(31,537,1), X_MASK, M601, { RA, RS, RB } }, + +{ "srd", XRC(31,539,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "srd.", XRC(31,539,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "maskir", XRC(31,541,0), X_MASK, M601, { RA, RS, RB } }, +{ "maskir.", XRC(31,541,1), X_MASK, M601, { RA, RS, RB } }, + +{ "lwbrxe", X(31,542), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "lfsxe", X(31,543), X_MASK, BOOKE64, { FRT, RA0, RB } }, + +{ "bbelr", X(31,550), X_MASK, PPCBRLK, { 0 }}, + +{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, + +{ "lfsux", X(31,567), X_MASK, COM, { FRT, RAS, RB } }, + +{ "lfsuxe", X(31,575), X_MASK, BOOKE64, { FRT, RAS, RB } }, + +{ "mfsr", X(31,595), XRB_MASK|(1<<20), COM32, { RT, SR } }, + +{ "lswi", X(31,597), X_MASK, PPCCOM, { RT, RA0, NB } }, +{ "lsi", X(31,597), X_MASK, PWRCOM, { RT, RA0, NB } }, + +{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPC, { 0 } }, +{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64, { 0 } }, +{ "msync", X(31,598), 0xffffffff, BOOKE, { 0 } }, +{ "sync", X(31,598), XSYNC_MASK, PPCCOM, { LS } }, +{ "dcs", X(31,598), 0xffffffff, PWRCOM, { 0 } }, + +{ "lfdx", X(31,599), X_MASK, COM, { FRT, RA0, RB } }, + +{ "lfdxe", X(31,607), X_MASK, BOOKE64, { FRT, RA0, RB } }, + +{ "mffgpr", XRC(31,607,0), XRA_MASK, POWER6, { FRT, RB } }, + +{ "mfsri", X(31,627), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dclst", X(31,630), XRB_MASK, PWRCOM, { RS, RA } }, + +{ "lfdux", X(31,631), X_MASK, COM, { FRT, RAS, RB } }, + +{ "lfduxe", X(31,639), X_MASK, BOOKE64, { FRT, RAS, RB } }, + +{ "mfsrin", X(31,659), XRA_MASK, PPC32, { RT, RB } }, + +{ "stdbrx", X(31,660), X_MASK, CELL, { RS, RA0, RB } }, + +{ "stswx", X(31,661), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stsx", X(31,661), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "stwbrx", X(31,662), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stbrx", X(31,662), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } }, + +{ "srq", XRC(31,664,0), X_MASK, M601, { RA, RS, RB } }, +{ "srq.", XRC(31,664,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sre", XRC(31,665,0), X_MASK, M601, { RA, RS, RB } }, +{ "sre.", XRC(31,665,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stwbrxe", X(31,670), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stfsxe", X(31,671), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "stfsux", X(31,695), X_MASK, COM, { FRS, RAS, RB } }, + +{ "sriq", XRC(31,696,0), X_MASK, M601, { RA, RS, SH } }, +{ "sriq.", XRC(31,696,1), X_MASK, M601, { RA, RS, SH } }, + +{ "stfsuxe", X(31,703), X_MASK, BOOKE64, { FRS, RAS, RB } }, + +{ "stswi", X(31,725), X_MASK, PPCCOM, { RS, RA0, NB } }, +{ "stsi", X(31,725), X_MASK, PWRCOM, { RS, RA0, NB } }, + +{ "stfdx", X(31,727), X_MASK, COM, { FRS, RA0, RB } }, + +{ "srlq", XRC(31,728,0), X_MASK, M601, { RA, RS, RB } }, +{ "srlq.", XRC(31,728,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sreq", XRC(31,729,0), X_MASK, M601, { RA, RS, RB } }, +{ "sreq.", XRC(31,729,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stfdxe", X(31,735), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "mftgpr", XRC(31,735,0), XRA_MASK, POWER6, { RT, FRB } }, + +{ "dcba", X(31,758), XRT_MASK, PPC405 | BOOKE, { RA, RB } }, + +{ "stfdux", X(31,759), X_MASK, COM, { FRS, RAS, RB } }, + +{ "srliq", XRC(31,760,0), X_MASK, M601, { RA, RS, SH } }, +{ "srliq.", XRC(31,760,1), X_MASK, M601, { RA, RS, SH } }, + +{ "dcbae", X(31,766), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "stfduxe", X(31,767), X_MASK, BOOKE64, { FRS, RAS, RB } }, + +{ "tlbivax", X(31,786), XRT_MASK, BOOKE, { RA, RB } }, +{ "tlbivaxe",X(31,787), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lwzcix", X(31,789), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "lhbrx", X(31,790), X_MASK, COM, { RT, RA0, RB } }, + +{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sra", XRC(31,792,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "sraw.", XRC(31,792,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sra.", XRC(31,792,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "srad", XRC(31,794,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "srad.", XRC(31,794,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "lhbrxe", X(31,798), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "ldxe", X(31,799), X_MASK, BOOKE64, { RT, RA0, RB } }, +{ "lduxe", X(31,831), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "rac", X(31,818), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lhzcix", X(31,821), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "dss", XDSS(31,822,0), XDSS_MASK, PPCVEC, { STRM } }, +{ "dssall", XDSS(31,822,1), XDSS_MASK, PPCVEC, { 0 } }, + +{ "srawi", XRC(31,824,0), X_MASK, PPCCOM, { RA, RS, SH } }, +{ "srai", XRC(31,824,0), X_MASK, PWRCOM, { RA, RS, SH } }, +{ "srawi.", XRC(31,824,1), X_MASK, PPCCOM, { RA, RS, SH } }, +{ "srai.", XRC(31,824,1), X_MASK, PWRCOM, { RA, RS, SH } }, + +{ "slbmfev", X(31,851), XRA_MASK, PPC64, { RT, RB } }, + +{ "lbzcix", X(31,853), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "mbar", X(31,854), X_MASK, BOOKE, { MO } }, +{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, + +{ "lfiwax", X(31,855), X_MASK, POWER6, { FRT, RA0, RB } }, + +{ "ldcix", X(31,885), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "tlbsx", XRC(31,914,0), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, +{ "tlbsx.", XRC(31,914,1), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, +{ "tlbsxe", XRC(31,915,0), X_MASK, BOOKE64, { RTO, RA, RB } }, +{ "tlbsxe.", XRC(31,915,1), X_MASK, BOOKE64, { RTO, RA, RB } }, + +{ "slbmfee", X(31,915), XRA_MASK, PPC64, { RT, RB } }, + +{ "stwcix", X(31,917), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "sthbrx", X(31,918), X_MASK, COM, { RS, RA0, RB } }, + +{ "sraq", XRC(31,920,0), X_MASK, M601, { RA, RS, RB } }, +{ "sraq.", XRC(31,920,1), X_MASK, M601, { RA, RS, RB } }, + +{ "srea", XRC(31,921,0), X_MASK, M601, { RA, RS, RB } }, +{ "srea.", XRC(31,921,1), X_MASK, M601, { RA, RS, RB } }, + +{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } }, +{ "exts", XRC(31,922,0), XRB_MASK, PWRCOM, { RA, RS } }, +{ "extsh.", XRC(31,922,1), XRB_MASK, PPCCOM, { RA, RS } }, +{ "exts.", XRC(31,922,1), XRB_MASK, PWRCOM, { RA, RS } }, + +{ "sthbrxe", X(31,926), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stdxe", X(31,927), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "tlbrehi", XTLB(31,946,0), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbrelo", XTLB(31,946,1), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbre", X(31,946), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, + +{ "sthcix", X(31,949), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "sraiq", XRC(31,952,0), X_MASK, M601, { RA, RS, SH } }, +{ "sraiq.", XRC(31,952,1), X_MASK, M601, { RA, RS, SH } }, + +{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, +{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, + +{ "stduxe", X(31,959), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "iccci", X(31,966), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "tlbwehi", XTLB(31,978,0), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbwelo", XTLB(31,978,1), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbwe", X(31,978), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, +{ "tlbld", X(31,978), XRTRA_MASK, PPC, { RB } }, + +{ "stbcix", X(31,981), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, + +{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA0, RB } }, + +{ "extsw", XRC(31,986,0), XRB_MASK, PPC64 | BOOKE64,{ RA, RS } }, +{ "extsw.", XRC(31,986,1), XRB_MASK, PPC64, { RA, RS } }, + +{ "icread", X(31,998), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "icbie", X(31,990), XRT_MASK, BOOKE64, { RA, RB } }, +{ "stfiwxe", X(31,991), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "tlbli", X(31,1010), XRTRA_MASK, PPC, { RB } }, + +{ "stdcix", X(31,1013), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "dcbzl", XOPL(31,1014,1), XRT_MASK,POWER4, { RA, RB } }, +{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, +{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, + +{ "dcbze", X(31,1022), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lvebx", X(31, 7), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvehx", X(31, 39), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvewx", X(31, 71), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvsl", X(31, 6), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvsr", X(31, 38), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvx", X(31, 103), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvxl", X(31, 359), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "stvebx", X(31, 135), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvehx", X(31, 167), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvewx", X(31, 199), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvx", X(31, 231), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvxl", X(31, 487), X_MASK, PPCVEC, { VS, RA, RB } }, + +/* New load/store left/right index vector instructions that are in the Cell only. */ +{ "lvlx", X(31, 519), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvlxl", X(31, 775), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvrx", X(31, 551), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvrxl", X(31, 807), X_MASK, CELL, { VD, RA0, RB } }, +{ "stvlx", X(31, 647), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvlxl", X(31, 903), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvrx", X(31, 679), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvrxl", X(31, 935), X_MASK, CELL, { VS, RA0, RB } }, + +{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } }, +{ "l", OP(32), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "lwzu", OP(33), OP_MASK, PPCCOM, { RT, D, RAL } }, +{ "lu", OP(33), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lbzu", OP(35), OP_MASK, COM, { RT, D, RAL } }, + +{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } }, +{ "st", OP(36), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } }, +{ "stu", OP(37), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } }, + +{ "stbu", OP(39), OP_MASK, COM, { RS, D, RAS } }, + +{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lhzu", OP(41), OP_MASK, COM, { RT, D, RAL } }, + +{ "lha", OP(42), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lhau", OP(43), OP_MASK, COM, { RT, D, RAL } }, + +{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } }, + +{ "sthu", OP(45), OP_MASK, COM, { RS, D, RAS } }, + +{ "lmw", OP(46), OP_MASK, PPCCOM, { RT, D, RAM } }, +{ "lm", OP(46), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "stmw", OP(47), OP_MASK, PPCCOM, { RS, D, RA0 } }, +{ "stm", OP(47), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } }, + +{ "lfsu", OP(49), OP_MASK, COM, { FRT, D, RAS } }, + +{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } }, + +{ "lfdu", OP(51), OP_MASK, COM, { FRT, D, RAS } }, + +{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } }, + +{ "stfsu", OP(53), OP_MASK, COM, { FRS, D, RAS } }, + +{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } }, + +{ "stfdu", OP(55), OP_MASK, COM, { FRS, D, RAS } }, + +{ "lq", OP(56), OP_MASK, POWER4, { RTQ, DQ, RAQ } }, + +{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA0 } }, + +{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA0 } }, + +{ "lfdp", OP(57), OP_MASK, POWER6, { FRT, D, RA0 } }, + +{ "lbze", DEO(58,0), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lbzue", DEO(58,1), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lhze", DEO(58,2), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lhzue", DEO(58,3), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lhae", DEO(58,4), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lhaue", DEO(58,5), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lwze", DEO(58,6), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lwzue", DEO(58,7), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "stbe", DEO(58,8), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "stbue", DEO(58,9), DE_MASK, BOOKE64, { RS, DE, RAS } }, +{ "sthe", DEO(58,10), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "sthue", DEO(58,11), DE_MASK, BOOKE64, { RS, DE, RAS } }, +{ "stwe", DEO(58,14), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "stwue", DEO(58,15), DE_MASK, BOOKE64, { RS, DE, RAS } }, + +{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } }, + +{ "ldu", DSO(58,1), DS_MASK, PPC64, { RT, DS, RAL } }, + +{ "lwa", DSO(58,2), DS_MASK, PPC64, { RT, DS, RA0 } }, + +{ "dadd", XRC(59,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dadd.", XRC(59,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dqua", ZRC(59,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "dqua.", ZRC(59,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fres", A(59,24,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, +{ "fres.", A(59,24,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, + +{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, + +{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, +{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, + +{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "dmul", XRC(59,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dmul.", XRC(59,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "drrnd", ZRC(59,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "drrnd.", ZRC(59,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "dscli", ZRC(59,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscli.", ZRC(59,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "dquai", ZRC(59,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, +{ "dquai.", ZRC(59,67,1), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, + +{ "dscri", ZRC(59,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscri.", ZRC(59,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "drintx", ZRC(59,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintx.", ZRC(59,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dcmpo", X(59,130), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstex", X(59,162), X_MASK, POWER6, { BF, FRA, FRB } }, +{ "dtstdc", Z(59,194), Z_MASK, POWER6, { BF, FRA, DCM } }, +{ "dtstdg", Z(59,226), Z_MASK, POWER6, { BF, FRA, DGM } }, + +{ "drintn", ZRC(59,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintn.", ZRC(59,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dctdp", XRC(59,258,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctdp.", XRC(59,258,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dctfix", XRC(59,290,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctfix.", XRC(59,290,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "ddedpd", XRC(59,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, +{ "ddedpd.", XRC(59,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, + +{ "dxex", XRC(59,354,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dxex.", XRC(59,354,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dsub", XRC(59,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dsub.", XRC(59,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "ddiv", XRC(59,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "ddiv.", XRC(59,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dcmpu", X(59,642), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstsf", X(59,674), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "drsp", XRC(59,770,0), X_MASK, POWER6, { FRT, FRB } }, +{ "drsp.", XRC(59,770,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dcffix", XRC(59,802,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dcffix.", XRC(59,802,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "denbcd", XRC(59,834,0), X_MASK, POWER6, { S, FRT, FRB } }, +{ "denbcd.", XRC(59,834,1), X_MASK, POWER6, { S, FRT, FRB } }, + +{ "diex", XRC(59,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "diex.", XRC(59,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfdp", OP(61), OP_MASK, POWER6, { FRT, D, RA0 } }, + +{ "lde", DEO(62,0), DE_MASK, BOOKE64, { RT, DES, RA0 } }, +{ "ldue", DEO(62,1), DE_MASK, BOOKE64, { RT, DES, RA0 } }, +{ "lfse", DEO(62,4), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, +{ "lfsue", DEO(62,5), DE_MASK, BOOKE64, { FRT, DES, RAS } }, +{ "lfde", DEO(62,6), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, +{ "lfdue", DEO(62,7), DE_MASK, BOOKE64, { FRT, DES, RAS } }, +{ "stde", DEO(62,8), DE_MASK, BOOKE64, { RS, DES, RA0 } }, +{ "stdue", DEO(62,9), DE_MASK, BOOKE64, { RS, DES, RAS } }, +{ "stfse", DEO(62,12), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, +{ "stfsue", DEO(62,13), DE_MASK, BOOKE64, { FRS, DES, RAS } }, +{ "stfde", DEO(62,14), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, +{ "stfdue", DEO(62,15), DE_MASK, BOOKE64, { FRS, DES, RAS } }, + +{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } }, + +{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } }, + +{ "stq", DSO(62,2), DS_MASK, POWER4, { RSQ, DS, RA0 } }, + +{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, + +{ "daddq", XRC(63,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "daddq.", XRC(63,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dquaq", ZRC(63,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "dquaq.", ZRC(63,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "fcpsgn", XRC(63,8,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "fcpsgn.", XRC(63,8,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } }, +{ "frsp.", XRC(63,12,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "fctiw", XRC(63,14,0), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiw.", XRC(63,14,1), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fdiv", A(63,18,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fd", A(63,18,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fdiv.", A(63,18,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fd.", A(63,18,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fs", A(63,20,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fsub.", A(63,20,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fs.", A(63,20,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fadd", A(63,21,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fa", A(63,21,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fadd.", A(63,21,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fa.", A(63,21,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, +{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, + +{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fre", A(63,24,0), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, +{ "fre.", A(63,24,1), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, + +{ "fmul", A(63,25,0), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, +{ "fm", A(63,25,0), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, +{ "fmul.", A(63,25,1), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, +{ "fm.", A(63,25,1), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, + +{ "frsqrte", A(63,26,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, +{ "frsqrte.",A(63,26,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, + +{ "fmsub", A(63,28,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fms", A(63,28,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fmsub.", A(63,28,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fms.", A(63,28,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fmadd", A(63,29,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fma", A(63,29,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fmadd.", A(63,29,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fma.", A(63,29,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fnmsub", A(63,30,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnms", A(63,30,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fnmsub.", A(63,30,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnms.", A(63,30,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fnmadd", A(63,31,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnma", A(63,31,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fnmadd.", A(63,31,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnma.", A(63,31,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fcmpo", X(63,32), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, + +{ "dmulq", XRC(63,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dmulq.", XRC(63,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "drrndq", ZRC(63,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "drrndq.", ZRC(63,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "mtfsb1", XRC(63,38,0), XRARB_MASK, COM, { BT } }, +{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, COM, { BT } }, + +{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fneg.", XRC(63,40,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), COM, { BF, BFA } }, + +{ "dscliq", ZRC(63,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscliq.", ZRC(63,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "dquaiq", ZRC(63,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, +{ "dquaiq.", ZRC(63,67,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "mtfsb0", XRC(63,70,0), XRARB_MASK, COM, { BT } }, +{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, COM, { BT } }, + +{ "fmr", XRC(63,72,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fmr.", XRC(63,72,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dscriq", ZRC(63,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscriq.", ZRC(63,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "drintxq", ZRC(63,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintxq.",ZRC(63,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dcmpoq", X(63,130), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "mtfsfi", XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, +{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, + +{ "fnabs", XRC(63,136,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fnabs.", XRC(63,136,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dtstexq", X(63,162), X_MASK, POWER6, { BF, FRA, FRB } }, +{ "dtstdcq", Z(63,194), Z_MASK, POWER6, { BF, FRA, DCM } }, +{ "dtstdgq", Z(63,226), Z_MASK, POWER6, { BF, FRA, DGM } }, + +{ "drintnq", ZRC(63,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintnq.",ZRC(63,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dctqpq", XRC(63,258,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctqpq.", XRC(63,258,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "fabs", XRC(63,264,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fabs.", XRC(63,264,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dctfixq", XRC(63,290,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctfixq.",XRC(63,290,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "ddedpdq", XRC(63,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, +{ "ddedpdq.",XRC(63,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, + +{ "dxexq", XRC(63,354,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dxexq.", XRC(63,354,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "frin", XRC(63,392,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frin.", XRC(63,392,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "friz", XRC(63,424,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "friz.", XRC(63,424,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frip", XRC(63,456,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frip.", XRC(63,456,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frim", XRC(63,488,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frim.", XRC(63,488,1), XRA_MASK, POWER5, { FRT, FRB } }, + +{ "dsubq", XRC(63,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dsubq.", XRC(63,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } }, +{ "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } }, + +{ "dcmpuq", X(63,642), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstsfq", X(63,674), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "mtfsf", XFL(63,711,0), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, +{ "mtfsf.", XFL(63,711,1), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, + +{ "drdpq", XRC(63,770,0), X_MASK, POWER6, { FRT, FRB } }, +{ "drdpq.", XRC(63,770,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dcffixq", XRC(63,802,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dcffixq.",XRC(63,802,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "fctid", XRC(63,814,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fctid.", XRC(63,814,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "fctidz", XRC(63,815,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "denbcdq", XRC(63,834,0), X_MASK, POWER6, { S, FRT, FRB } }, +{ "denbcdq.",XRC(63,834,1), X_MASK, POWER6, { S, FRT, FRB } }, + +{ "fcfid", XRC(63,846,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "diexq", XRC(63,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "diexq.", XRC(63,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +}; + +const int powerpc_num_opcodes = + sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); + +/* The macro table. This is only used by the assembler. */ + +/* The expressions of the form (-x ! 31) & (x | 31) have the value 0 + when x=0; 32-x when x is between 1 and 31; are negative if x is + negative; and are 32 or more otherwise. This is what you want + when, for instance, you are emulating a right shift by a + rotate-left-and-mask, because the underlying instructions support + shifts of size 0 but not shifts of size 32. By comparison, when + extracting x bits from some word you want to use just 32-x, because + the underlying instructions don't support extracting 0 bits but do + support extracting the whole word (32 bits in this case). */ + +const struct powerpc_macro powerpc_macros[] = { +{ "extldi", 4, PPC64, "rldicr %0,%1,%3,(%2)-1" }, +{ "extldi.", 4, PPC64, "rldicr. %0,%1,%3,(%2)-1" }, +{ "extrdi", 4, PPC64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, +{ "extrdi.", 4, PPC64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, +{ "insrdi", 4, PPC64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, +{ "insrdi.", 4, PPC64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, +{ "rotrdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),0" }, +{ "rotrdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" }, +{ "sldi", 3, PPC64, "rldicr %0,%1,%2,63-(%2)" }, +{ "sldi.", 3, PPC64, "rldicr. %0,%1,%2,63-(%2)" }, +{ "srdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" }, +{ "srdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" }, +{ "clrrdi", 3, PPC64, "rldicr %0,%1,0,63-(%2)" }, +{ "clrrdi.", 3, PPC64, "rldicr. %0,%1,0,63-(%2)" }, +{ "clrlsldi",4, PPC64, "rldic %0,%1,%3,(%2)-(%3)" }, +{ "clrlsldi.",4, PPC64, "rldic. %0,%1,%3,(%2)-(%3)" }, + +{ "extlwi", 4, PPCCOM, "rlwinm %0,%1,%3,0,(%2)-1" }, +{ "extlwi.", 4, PPCCOM, "rlwinm. %0,%1,%3,0,(%2)-1" }, +{ "extrwi", 4, PPCCOM, "rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, +{ "extrwi.", 4, PPCCOM, "rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, +{ "inslwi", 4, PPCCOM, "rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" }, +{ "inslwi.", 4, PPCCOM, "rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"}, +{ "insrwi", 4, PPCCOM, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, +{ "insrwi.", 4, PPCCOM, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, +{ "rotrwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" }, +{ "rotrwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" }, +{ "slwi", 3, PPCCOM, "rlwinm %0,%1,%2,0,31-(%2)" }, +{ "sli", 3, PWRCOM, "rlinm %0,%1,%2,0,31-(%2)" }, +{ "slwi.", 3, PPCCOM, "rlwinm. %0,%1,%2,0,31-(%2)" }, +{ "sli.", 3, PWRCOM, "rlinm. %0,%1,%2,0,31-(%2)" }, +{ "srwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "sri", 3, PWRCOM, "rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "srwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "sri.", 3, PWRCOM, "rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "clrrwi", 3, PPCCOM, "rlwinm %0,%1,0,0,31-(%2)" }, +{ "clrrwi.", 3, PPCCOM, "rlwinm. %0,%1,0,0,31-(%2)" }, +{ "clrlslwi",4, PPCCOM, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, +{ "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, +}; + +const int powerpc_num_macros = + sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); + + +/* This file provides several disassembler functions, all of which use + the disassembler interface defined in dis-asm.h. Several functions + are provided because this file handles disassembly for the PowerPC + in both big and little endian mode and also for the POWER (RS/6000) + chip. */ + +static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); + +/* Determine which set of machines to disassemble for. PPC403/601 or + BookE. For convenience, also disassemble instructions supported + by the AltiVec vector unit. */ + +static int +powerpc_dialect (struct disassemble_info *info) +{ + int dialect = PPC_OPCODE_PPC; + + if (BFD_DEFAULT_TARGET_SIZE == 64) + dialect |= PPC_OPCODE_64; + + if (info->disassembler_options + && strstr (info->disassembler_options, "booke") != NULL) + dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; + else if ((info->mach == bfd_mach_ppc_e500) + || (info->disassembler_options + && strstr (info->disassembler_options, "e500") != NULL)) + dialect |= (PPC_OPCODE_BOOKE + | PPC_OPCODE_SPE | PPC_OPCODE_ISEL + | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK + | PPC_OPCODE_RFMCI); + else if (info->disassembler_options + && strstr (info->disassembler_options, "efs") != NULL) + dialect |= PPC_OPCODE_EFS; + else if (info->disassembler_options + && strstr (info->disassembler_options, "e300") != NULL) + dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; + else if (info->disassembler_options + && strstr (info->disassembler_options, "440") != NULL) + dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 + | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; + else + dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC + | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); + + if (info->disassembler_options + && strstr (info->disassembler_options, "power4") != NULL) + dialect |= PPC_OPCODE_POWER4; + + if (info->disassembler_options + && strstr (info->disassembler_options, "power5") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; + + if (info->disassembler_options + && strstr (info->disassembler_options, "cell") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; + + if (info->disassembler_options + && strstr (info->disassembler_options, "power6") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; + + if (info->disassembler_options + && strstr (info->disassembler_options, "any") != NULL) + dialect |= PPC_OPCODE_ANY; + + if (info->disassembler_options) + { + if (strstr (info->disassembler_options, "32") != NULL) + dialect &= ~PPC_OPCODE_64; + else if (strstr (info->disassembler_options, "64") != NULL) + dialect |= PPC_OPCODE_64; + } + + info->private_data = (char *) 0 + dialect; + return dialect; +} + +/* Qemu default */ +int +print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 1, dialect); +} + +/* Print a big endian PowerPC instruction. */ + +int +print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 1, dialect); +} + +/* Print a little endian PowerPC instruction. */ + +int +print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 0, dialect); +} + +/* Print a POWER (RS/6000) instruction. */ + +int +print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) +{ + return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); +} + +/* Extract the operand value from the PowerPC or POWER instruction. */ + +static long +operand_value_powerpc (const struct powerpc_operand *operand, + unsigned long insn, int dialect) +{ + long value; + int invalid; + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, dialect, &invalid); + else + { + value = (insn >> operand->shift) & operand->bitm; + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + { + /* BITM is always some number of zeros followed by some + number of ones, followed by some numer of zeros. */ + unsigned long top = operand->bitm; + /* top & -top gives the rightmost 1 bit, so this + fills in any trailing zeros. */ + top |= (top & -top) - 1; + top &= ~(top >> 1); + value = (value ^ top) - top; + } + } + + return value; +} + +/* Determine whether the optional operand(s) should be printed. */ + +static int +skip_optional_operands (const unsigned char *opindex, + unsigned long insn, int dialect) +{ + const struct powerpc_operand *operand; + + for (; *opindex != 0; opindex++) + { + operand = &powerpc_operands[*opindex]; + if ((operand->flags & PPC_OPERAND_NEXT) != 0 + || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 + && operand_value_powerpc (operand, insn, dialect) != 0)) + return 0; + } + + return 1; +} + +/* Print a PowerPC or POWER instruction. */ + +static int +print_insn_powerpc (bfd_vma memaddr, + struct disassemble_info *info, + int bigendian, + int dialect) +{ + bfd_byte buffer[4]; + int status; + unsigned long insn; + const struct powerpc_opcode *opcode; + const struct powerpc_opcode *opcode_end; + unsigned long op; + + if (dialect == 0) + dialect = powerpc_dialect (info); + + status = (*info->read_memory_func) (memaddr, buffer, 4, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + if (bigendian) + insn = bfd_getb32 (buffer); + else + insn = bfd_getl32 (buffer); + + /* Get the major opcode of the instruction. */ + op = PPC_OP (insn); + + /* Find the first match in the opcode table. We could speed this up + a bit by doing a binary search on the major opcode. */ + opcode_end = powerpc_opcodes + powerpc_num_opcodes; + again: + for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + { + unsigned long table_op; + const unsigned char *opindex; + const struct powerpc_operand *operand; + int invalid; + int need_comma; + int need_paren; + int skip_optional; + + table_op = PPC_OP (opcode->opcode); + if (op < table_op) + break; + if (op > table_op) + continue; + + if ((insn & opcode->mask) != opcode->opcode + || (opcode->flags & dialect) == 0) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + operand = powerpc_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, dialect, &invalid); + } + if (invalid) + continue; + + /* The instruction is valid. */ + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* Now extract and print the operands. */ + need_comma = 0; + need_paren = 0; + skip_optional = -1; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + long value; + + operand = powerpc_operands + *opindex; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & PPC_OPERAND_FAKE) != 0) + continue; + + /* If all of the optional operands have the value zero, + then don't print any of them. */ + if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) + { + if (skip_optional < 0) + skip_optional = skip_optional_operands (opindex, insn, + dialect); + if (skip_optional) + continue; + } + + value = operand_value_powerpc (operand, insn, dialect); + + if (need_comma) + { + (*info->fprintf_func) (info->stream, ","); + need_comma = 0; + } + + /* Print the operand as directed by the flags. */ + if ((operand->flags & PPC_OPERAND_GPR) != 0 + || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) + (*info->fprintf_func) (info->stream, "r%ld", value); + else if ((operand->flags & PPC_OPERAND_FPR) != 0) + (*info->fprintf_func) (info->stream, "f%ld", value); + else if ((operand->flags & PPC_OPERAND_VR) != 0) + (*info->fprintf_func) (info->stream, "v%ld", value); + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) + (*info->print_address_func) (memaddr + value, info); + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) + (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); + else if ((operand->flags & PPC_OPERAND_CR) == 0 + || (dialect & PPC_OPCODE_PPC) == 0) + (*info->fprintf_func) (info->stream, "%ld", value); + else + { + if (operand->bitm == 7) + (*info->fprintf_func) (info->stream, "cr%ld", value); + else + { + static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; + int cr; + int cc; + + cr = value >> 2; + if (cr != 0) + (*info->fprintf_func) (info->stream, "4*cr%d+", cr); + cc = value & 3; + (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); + } + } + + if (need_paren) + { + (*info->fprintf_func) (info->stream, ")"); + need_paren = 0; + } + + if ((operand->flags & PPC_OPERAND_PARENS) == 0) + need_comma = 1; + else + { + (*info->fprintf_func) (info->stream, "("); + need_paren = 1; + } + } + + /* We have found and printed an instruction; return. */ + return 4; + } + + if ((dialect & PPC_OPCODE_ANY) != 0) + { + dialect = ~PPC_OPCODE_ANY; + goto again; + } + + /* We could not find a match. */ + (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); + + return 4; +} diff --git a/qemu/qemu-git/.svn/text-base/ppc.ld.svn-base b/qemu/qemu-git/.svn/text-base/ppc.ld.svn-base new file mode 100644 index 0000000..5248ef1 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/ppc.ld.svn-base @@ -0,0 +1,227 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glink) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + PROVIDE (_SDA2_BASE_ = 32768); + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .got1 : { *(.got1) } + .got2 : { *(.got2) } + .dynamic : { *(.dynamic) } + .got : SPECIAL { *(.got) } + . = DATA_SEGMENT_RELRO_END (0, .); + .plt : SPECIAL { *(.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .got : SPECIAL { *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + PROVIDE (_SDA_BASE_ = 32768); + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); + } + .plt : SPECIAL { *(.plt) } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /DISCARD/ : { *(.fixup) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/.svn/text-base/ppc64.ld.svn-base b/qemu/qemu-git/.svn/text-base/ppc64.ld.svn-base new file mode 100644 index 0000000..dea0dbd --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/ppc64.ld.svn-base @@ -0,0 +1,220 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", + "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.toc) + *(.rela.opd) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.tocbss : { *(.rela.tocbss) } + .init : + { + KEEP (*(.init)) + } =0x60000000 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.sfpr .glink) + } =0x60000000 + .fini : + { + KEEP (*(.fini)) + } =0x60000000 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Adjust the address for the data segment. We want to +adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN +(0x10000, 0x1000); /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } + PROVIDE (__fini_array_end = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .toc1 ALIGN(8) : { *(.toc1) } + .opd ALIGN(8) : { KEEP (*(.opd)) } + .got ALIGN(8) : { *(.got .toc) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .tocbss ALIGN(8) : { *(.tocbss)} + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/.svn/text-base/qemu-common.h.svn-base b/qemu/qemu-git/.svn/text-base/qemu-common.h.svn-base new file mode 100644 index 0000000..8630f8c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/qemu-common.h.svn-base @@ -0,0 +1,275 @@ +/* Common header file that is included by all of qemu. */ +#ifndef QEMU_COMMON_H +#define QEMU_COMMON_H + +#define QEMU_NORETURN __attribute__ ((__noreturn__)) +#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT +#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define QEMU_WARN_UNUSED_RESULT +#endif + +/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that + cannot include the following headers without conflicts. This condition has + to be removed once dyngen is gone. */ +#ifndef __DYNGEN_EXEC_H__ + +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config-host.h" + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif +#if !defined(ENOTSUP) +#define ENOTSUP 4096 +#endif + +#ifndef CONFIG_IOVEC +#define CONFIG_IOVEC +struct iovec { + void *iov_base; + size_t iov_len; +}; +#else +#include +#endif + +#ifdef _WIN32 +#define fsync _commit +#define lseek _lseeki64 +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" +#endif + +/* FIXME: Remove NEED_CPU_H. */ +#ifndef NEED_CPU_H + +#include +#include "osdep.h" +#include "bswap.h" + +#else + +#include "cpu.h" + +#endif /* !defined(NEED_CPU_H) */ + +/* bottom halves */ +typedef struct QEMUBH QEMUBH; + +typedef void QEMUBHFunc(void *opaque); + +void async_context_push(void); +void async_context_pop(void); +int get_async_context_id(void); + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +void qemu_bh_schedule(QEMUBH *bh); +/* Bottom halfs that are scheduled from a bottom half handler are instantly + * invoked. This can create an infinite loop if a bottom half handler + * schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by + * ensuring that the bottom half isn't executed until the next main loop + * iteration. + */ +void qemu_bh_schedule_idle(QEMUBH *bh); +void qemu_bh_cancel(QEMUBH *bh); +void qemu_bh_delete(QEMUBH *bh); +int qemu_bh_poll(void); +void qemu_bh_update_timeout(int *timeout); + +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); + +void qemu_get_timedate(struct tm *tm, int offset); +int qemu_timedate_diff(struct tm *tm); + +/* cutils.c */ +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +int qemu_strnlen(const char *s, int max_len); +time_t mktimegm(struct tm *tm); +int qemu_fls(int i); +int qemu_fdatasync(int fd); + +/* path.c */ +void init_paths(const char *prefix); +const char *path(const char *pathname); + +#define qemu_isalnum(c) isalnum((unsigned char)(c)) +#define qemu_isalpha(c) isalpha((unsigned char)(c)) +#define qemu_iscntrl(c) iscntrl((unsigned char)(c)) +#define qemu_isdigit(c) isdigit((unsigned char)(c)) +#define qemu_isgraph(c) isgraph((unsigned char)(c)) +#define qemu_islower(c) islower((unsigned char)(c)) +#define qemu_isprint(c) isprint((unsigned char)(c)) +#define qemu_ispunct(c) ispunct((unsigned char)(c)) +#define qemu_isspace(c) isspace((unsigned char)(c)) +#define qemu_isupper(c) isupper((unsigned char)(c)) +#define qemu_isxdigit(c) isxdigit((unsigned char)(c)) +#define qemu_tolower(c) tolower((unsigned char)(c)) +#define qemu_toupper(c) toupper((unsigned char)(c)) +#define qemu_isascii(c) isascii((unsigned char)(c)) +#define qemu_toascii(c) toascii((unsigned char)(c)) + +void *qemu_malloc(size_t size); +void *qemu_realloc(void *ptr, size_t size); +void *qemu_mallocz(size_t size); +void qemu_free(void *ptr); +char *qemu_strdup(const char *str); +char *qemu_strndup(const char *str, size_t size); + +void *get_mmap_addr(unsigned long size); + + +void qemu_mutex_lock_iothread(void); +void qemu_mutex_unlock_iothread(void); + +int qemu_open(const char *name, int flags, ...); +void qemu_set_cloexec(int fd); + +#ifndef _WIN32 +int qemu_pipe(int pipefd[2]); +#endif + +/* Error handling. */ + +void QEMU_NORETURN hw_error(const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +/* IO callbacks. */ +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); +typedef void IOHandler(void *opaque); + +struct ParallelIOArg { + void *buffer; + int count; +}; + +typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); + +/* A load of opaque types so that device init declarations don't have to + pull in all the real definitions. */ +typedef struct NICInfo NICInfo; +typedef struct HCIInfo HCIInfo; +typedef struct AudioState AudioState; +typedef struct BlockDriverState BlockDriverState; +typedef struct DisplayState DisplayState; +typedef struct DisplayChangeListener DisplayChangeListener; +typedef struct DisplaySurface DisplaySurface; +typedef struct DisplayAllocator DisplayAllocator; +typedef struct PixelFormat PixelFormat; +typedef struct TextConsole TextConsole; +typedef TextConsole QEMUConsole; +typedef struct CharDriverState CharDriverState; +typedef struct MACAddr MACAddr; +typedef struct VLANState VLANState; +typedef struct VLANClientState VLANClientState; +typedef struct QEMUFile QEMUFile; +typedef struct i2c_bus i2c_bus; +typedef struct i2c_slave i2c_slave; +typedef struct SMBusDevice SMBusDevice; +typedef struct QEMUTimer QEMUTimer; +typedef struct PCIHostState PCIHostState; +typedef struct PCIExpressHost PCIExpressHost; +typedef struct PCIBus PCIBus; +typedef struct PCIDevice PCIDevice; +typedef struct SerialState SerialState; +typedef struct IRQState *qemu_irq; +typedef struct PCMCIACardState PCMCIACardState; +typedef struct MouseTransformInfo MouseTransformInfo; +typedef struct uWireSlave uWireSlave; +typedef struct I2SCodec I2SCodec; +typedef struct DeviceState DeviceState; +typedef struct SSIBus SSIBus; + +/* CPU save/load. */ +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + +/* Force QEMU to stop what it's doing and service IO */ +void qemu_service_io(void); + +/* Force QEMU to process pending events */ +void qemu_notify_event(void); + +/* Unblock cpu */ +void qemu_cpu_kick(void *env); +int qemu_cpu_self(void *env); + +#ifdef CONFIG_USER_ONLY +#define qemu_init_vcpu(env) do { } while (0) +#else +void qemu_init_vcpu(void *env); +#endif + +typedef struct QEMUIOVector { + struct iovec *iov; + int niov; + int nalloc; + size_t size; +} QEMUIOVector; + +void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); +void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); +void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); +void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size); +void qemu_iovec_destroy(QEMUIOVector *qiov); +void qemu_iovec_reset(QEMUIOVector *qiov); +void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf); +void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count); + +struct Monitor; +typedef struct Monitor Monitor; + +/* Convert a byte between binary and BCD. */ +static inline uint8_t to_bcd(uint8_t val) +{ + return ((val / 10) << 4) | (val % 10); +} + +static inline uint8_t from_bcd(uint8_t val) +{ + return ((val >> 4) * 10) + (val & 0x0f); +} + +#include "module.h" + +#endif /* dyngen-exec.h hack */ + +#endif diff --git a/qemu/qemu-git/.svn/text-base/qemu-lock.h.svn-base b/qemu/qemu-git/.svn/text-base/qemu-lock.h.svn-base new file mode 100644 index 0000000..9a3e6ac --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/qemu-lock.h.svn-base @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +/* Locking primitives. Most of this code should be redundant - + system emulation doesn't need/use locking, NPTL userspace uses + pthread mutexes, and non-NPTL userspace isn't threadsafe anyway. + In either case a spinlock is probably the wrong kind of lock. + Spinlocks are only good if you know annother CPU has the lock and is + likely to release it soon. In environments where you have more threads + than physical CPUs (the extreme case being a single CPU host) a spinlock + simply wastes CPU until the OS decides to preempt it. */ +#if defined(CONFIG_USE_NPTL) + +#include +#define spin_lock pthread_mutex_lock +#define spin_unlock pthread_mutex_unlock +#define spinlock_t pthread_mutex_t +#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER + +#else + +#if defined(__hppa__) + +typedef int spinlock_t[4]; + +#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 } + +static inline void resetlock (spinlock_t *p) +{ + (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1; +} + +#else + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +static inline void resetlock (spinlock_t *p) +{ + *p = SPIN_LOCK_UNLOCKED; +} + +#endif + +#if defined(_ARCH_PPC) +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + " lwarx %0,0,%1\n" + " xor. %0,%3,%0\n" + " bne $+12\n" + " stwcx. %2,0,%1\n" + " bne- $-16\n" + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#elif defined(__i386__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__x86_64__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__s390__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#elif defined(__alpha__) +static inline int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#elif defined(__sparc__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#elif defined(__arm__) +static inline int testandset (int *spinlock) +{ + register unsigned int ret; + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} +#elif defined(__mc68000) +static inline int testandset (int *p) +{ + char ret; + __asm__ __volatile__("tas %1; sne %0" + : "=r" (ret) + : "m" (p) + : "cc","memory"); + return ret; +} +#elif defined(__hppa__) + +/* Because malloc only guarantees 8-byte alignment for malloc'd data, + and GCC only guarantees 8-byte alignment for stack locals, we can't + be assured of 16-byte alignment for atomic lock data even if we + specify "__attribute ((aligned(16)))" in the type declaration. So, + we use a struct containing an array of four ints for the atomic lock + type and dynamically select the 16-byte aligned int from the array + for the semaphore. */ +#define __PA_LDCW_ALIGNMENT 16 +static inline void *ldcw_align (void *p) { + unsigned long a = (unsigned long)p; + a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); + return (void *)a; +} + +static inline int testandset (spinlock_t *p) +{ + unsigned int ret; + p = ldcw_align(p); + __asm__ __volatile__("ldcw 0(%1),%0" + : "=r" (ret) + : "r" (p) + : "memory" ); + return !ret; +} + +#elif defined(__ia64) + +#include + +static inline int testandset (int *p) +{ + return __sync_lock_test_and_set (p, 1); +} +#elif defined(__mips__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ( + " .set push \n" + " .set noat \n" + " .set mips2 \n" + "1: li $1, 1 \n" + " ll %0, %1 \n" + " sc $1, %1 \n" + " beqz $1, 1b \n" + " .set pop " + : "=r" (ret), "+R" (*p) + : + : "memory"); + + return ret; +} +#else +#error unimplemented CPU support +#endif + +#if defined(CONFIG_USER_ONLY) +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + resetlock(lock); +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} +#else +static inline void spin_lock(spinlock_t *lock) +{ +} + +static inline void spin_unlock(spinlock_t *lock) +{ +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return 1; +} +#endif + +#endif diff --git a/qemu/qemu-git/.svn/text-base/qemu-log.h.svn-base b/qemu/qemu-git/.svn/text-base/qemu-log.h.svn-base new file mode 100644 index 0000000..fccfb11 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/qemu-log.h.svn-base @@ -0,0 +1,93 @@ +#ifndef QEMU_LOG_H +#define QEMU_LOG_H + +/* The deprecated global variables: */ +extern FILE *logfile; +extern int loglevel; + + +/* + * The new API: + * + */ + +/* Log settings checking macros: */ + +/* Returns true if qemu_log() will really write somewhere + */ +#define qemu_log_enabled() (logfile != NULL) + +/* Returns true if a bit is set in the current loglevel mask + */ +#define qemu_loglevel_mask(b) ((loglevel & (b)) != 0) + + +/* Logging functions: */ + +/* main logging function + */ +#define qemu_log(...) do { \ + if (logfile) \ + fprintf(logfile, ## __VA_ARGS__); \ + } while (0) + +/* vfprintf-like logging function + */ +#define qemu_log_vprintf(fmt, va) do { \ + if (logfile) \ + vfprintf(logfile, fmt, va); \ + } while (0) + +/* log only if a bit is set on the current loglevel mask + */ +#define qemu_log_mask(b, ...) do { \ + if (loglevel & (b)) \ + fprintf(logfile, ## __VA_ARGS__); \ + } while (0) + + + + +/* Special cases: */ + +/* cpu_dump_state() logging functions: */ +#define log_cpu_state(env, f) cpu_dump_state((env), logfile, fprintf, (f)); +#define log_cpu_state_mask(b, env, f) do { \ + if (loglevel & (b)) log_cpu_state((env), (f)); \ + } while (0) + +/* disas() and target_disas() to logfile: */ +#define log_target_disas(start, len, flags) \ + target_disas(logfile, (start), (len), (flags)) +#define log_disas(start, len) \ + disas(logfile, (start), (len)) + +/* page_dump() output to the log file: */ +#define log_page_dump() page_dump(logfile) + + + +/* Maintenance: */ + +/* fflush() the log file */ +#define qemu_log_flush() fflush(logfile) + +/* Close the log file */ +#define qemu_log_close() do { \ + fclose(logfile); \ + logfile = NULL; \ + } while (0) + +/* Set up a new log file */ +#define qemu_log_set_file(f) do { \ + logfile = (f); \ + } while (0) + +/* Set up a new log file, only if none is set */ +#define qemu_log_try_set_file(f) do { \ + if (!logfile) \ + logfile = (f); \ + } while (0) + + +#endif diff --git a/qemu/qemu-git/.svn/text-base/qemu-malloc.c.svn-base b/qemu/qemu-git/.svn/text-base/qemu-malloc.c.svn-base new file mode 100644 index 0000000..5d9e34d --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/qemu-malloc.c.svn-base @@ -0,0 +1,102 @@ +/* + * malloc-like functions for system emulation. + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include + +static void *oom_check(void *ptr) +{ + if (ptr == NULL) { + abort(); + } + return ptr; +} + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +static int allow_zero_malloc(void) +{ +#if defined(CONFIG_ZERO_MALLOC) + return 1; +#else + return 0; +#endif +} + +void *qemu_malloc(size_t size) +{ + if (!size && !allow_zero_malloc()) { + abort(); + } + return oom_check(malloc(size ? size : 1)); +} + +void *qemu_realloc(void *ptr, size_t size) +{ + if (size) { + return oom_check(realloc(ptr, size)); + } else if (allow_zero_malloc()) { + return oom_check(realloc(ptr, size ? size : 1)); + } + abort(); +} + +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + memset(ptr, 0, size); + return ptr; +} + +char *qemu_strdup(const char *str) +{ + char *ptr; + size_t len = strlen(str); + ptr = qemu_malloc(len + 1); + memcpy(ptr, str, len + 1); + return ptr; +} + +char *qemu_strndup(const char *str, size_t size) +{ + const char *end = memchr(str, 0, size); + char *new; + + if (end) { + size = end - str; + } + + new = qemu_malloc(size + 1); + new[size] = 0; + + return memcpy(new, str, size); +} diff --git a/qemu/qemu-git/.svn/text-base/qemu-queue.h.svn-base b/qemu/qemu-git/.svn/text-base/qemu-queue.h.svn-base new file mode 100644 index 0000000..1d07745 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/qemu-queue.h.svn-base @@ -0,0 +1,449 @@ +/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */ + +/* + * Qemu version: Copy from netbsd, removed debug code, removed some of + * the implementations. Left in lists, simple queues, tail queues and + * circular queues. + */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef QEMU_SYS_QUEUE_H_ +#define QEMU_SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: + * lists, simple queues, tail queues, and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define QLIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define QLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define QLIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define QLIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define QLIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +#define QLIST_FOREACH_SAFE(var, head, field, next_var) \ + for ((var) = ((head)->lh_first); \ + (var) && ((next_var) = ((var)->field.le_next), 1); \ + (var) = (next_var)) + +/* + * List access methods. + */ +#define QLIST_EMPTY(head) ((head)->lh_first == NULL) +#define QLIST_FIRST(head) ((head)->lh_first) +#define QLIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Simple queue definitions. + */ +#define QSIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define QSIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define QSIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define QSIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + QSIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->sqh_first); \ + (var) && ((next = ((var)->field.sqe_next)), 1); \ + (var) = (next)) + +#define QSIMPLEQ_CONCAT(head1, head2) do { \ + if (!QSIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + QSIMPLEQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_LAST(head, type, field) \ + (QSIMPLEQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->sqh_last) - offsetof(struct type, field)))) + +/* + * Simple queue access methods. + */ +#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define QSIMPLEQ_FIRST(head) ((head)->sqh_first) +#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define Q_TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,) + +#define QTAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define Q_TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define QTAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \ + for ((var) = ((head)->tqh_first); \ + (var) && ((next_var) = ((var)->field.tqe_next), 1); \ + (var) = (next_var)) + +#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define QTAILQ_FIRST(head) ((head)->tqh_first) +#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define QTAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define QTAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define QCIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define QCIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define QCIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define QCIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define QCIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define QCIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define QCIRCLEQ_FIRST(head) ((head)->cqh_first) +#define QCIRCLEQ_LAST(head) ((head)->cqh_last) +#define QCIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define QCIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define QCIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define QCIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* !QEMU_SYS_QUEUE_H_ */ diff --git a/qemu/qemu-git/.svn/text-base/rules.mak.svn-base b/qemu/qemu-git/.svn/text-base/rules.mak.svn-base new file mode 100644 index 0000000..5941b73 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/rules.mak.svn-base @@ -0,0 +1,55 @@ + +# Don't use implicit rules or variables +# we have explicit rules for everything +MAKEFLAGS += -rR + +# Files with this suffixes are final, don't try to generate them +# using implicit rules +%.d: +%.h: +%.c: +%.m: +%.mak: + +# Flags for dependency generation +QEMU_DGFLAGS += -MMD -MP -MT $@ + +%.o: %.c + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@") + +%.o: %.S + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@") + +%.o: %.m + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") + +LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS)," LINK $(TARGET_DIR)$@") + +%$(EXESUF): %.o + $(call LINK,$^) + +%.a: + $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@") + +quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) + +# cc-option +# Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) + +cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ + >/dev/null 2>&1 && echo OK), $2, $3) + +VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi +set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES), $(eval vpath $(PATTERN) $1))) + +# Generate timestamp files for .h include files + +%.h: %.h-timestamp + @test -f $@ || cp $< $@ + +%.h-timestamp: %.mak + $(call quiet-command, sh $(SRC_PATH)/create_config < $< > $@, " GEN $*.h") + @cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h + +# will delete the target of a rule if commands exit with a nonzero exit status +.DELETE_ON_ERROR: diff --git a/qemu/qemu-git/.svn/text-base/s390-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/s390-dis.c.svn-base new file mode 100644 index 0000000..86dd84f --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/s390-dis.c.svn-base @@ -0,0 +1,1704 @@ +/* s390-dis.c -- Disassemble S390 instructions + Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of GDB, GAS and the GNU binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include +#include "dis-asm.h" + +/* s390.h -- Header file for S390 opcode table + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef S390_H +#define S390_H + +/* List of instruction sets variations. */ + +enum s390_opcode_mode_val + { + S390_OPCODE_ESA = 0, + S390_OPCODE_ZARCH + }; + +enum s390_opcode_cpu_val + { + S390_OPCODE_G5 = 0, + S390_OPCODE_G6, + S390_OPCODE_Z900, + S390_OPCODE_Z990, + S390_OPCODE_Z9_109, + S390_OPCODE_Z9_EC + }; + +/* The opcode table is an array of struct s390_opcode. */ + +struct s390_opcode + { + /* The opcode name. */ + const char * name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned char opcode[6]; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned char mask[6]; + + /* The opcode length in bytes. */ + int oplen; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[6]; + + /* Bitmask of execution modes this opcode is available for. */ + unsigned int modes; + + /* First cpu this opcode is available for. */ + enum s390_opcode_cpu_val min_cpu; + }; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct s390_opcode s390_opcodes[]; +extern const int s390_num_opcodes; + +/* A opcode format table for the .insn pseudo mnemonic. */ +extern const struct s390_opcode s390_opformats[]; +extern const int s390_num_opformats; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* The operands table is an array of struct s390_operand. */ + +struct s390_operand + { + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* One bit syntax flags. */ + unsigned long flags; + }; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct s390_operand s390_operands[]; + +/* Values defined for the flags field of a struct s390_operand. */ + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define S390_OPERAND_GPR 0x1 + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define S390_OPERAND_FPR 0x2 + +/* This operand names an access register. The disassembler + prints these with a leading 'a'. */ +#define S390_OPERAND_AR 0x4 + +/* This operand names a control register. The disassembler + prints these with a leading 'c'. */ +#define S390_OPERAND_CR 0x8 + +/* This operand is a displacement. */ +#define S390_OPERAND_DISP 0x10 + +/* This operand names a base register. */ +#define S390_OPERAND_BASE 0x20 + +/* This operand names an index register, it can be skipped. */ +#define S390_OPERAND_INDEX 0x40 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define S390_OPERAND_PCREL 0x80 + +/* This operand takes signed values. */ +#define S390_OPERAND_SIGNED 0x100 + +/* This operand is a length. */ +#define S390_OPERAND_LENGTH 0x200 + +/* This operand is optional. Only a single operand at the end of + the instruction may be optional. */ +#define S390_OPERAND_OPTIONAL 0x400 + + #endif /* S390_H */ + + +static int init_flag = 0; +static int opc_index[256]; +static int current_arch_mask = 0; + +/* Set up index table for first opcode byte. */ + +static void +init_disasm (struct disassemble_info *info) +{ + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + + memset (opc_index, 0, sizeof (opc_index)); + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes; opcode < opcode_end; opcode++) + { + opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes; + while ((opcode < opcode_end) && + (opcode[1].opcode[0] == opcode->opcode[0])) + opcode++; + } +// switch (info->mach) +// { +// case bfd_mach_s390_31: + current_arch_mask = 1 << S390_OPCODE_ESA; +// break; +// case bfd_mach_s390_64: +// current_arch_mask = 1 << S390_OPCODE_ZARCH; +// break; +// default: +// abort (); +// } + init_flag = 1; +} + +/* Extracts an operand value from an instruction. */ + +static inline unsigned int +s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) +{ + unsigned int val; + int bits; + + /* Extract fragments of the operand byte for byte. */ + insn += operand->shift / 8; + bits = (operand->shift & 7) + operand->bits; + val = 0; + do + { + val <<= 8; + val |= (unsigned int) *insn++; + bits -= 8; + } + while (bits > 0); + val >>= -bits; + val &= ((1U << (operand->bits - 1)) << 1) - 1; + + /* Check for special long displacement case. */ + if (operand->bits == 20 && operand->shift == 20) + val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; + + /* Sign extend value if the operand is signed or pc relative. */ + if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) + && (val & (1U << (operand->bits - 1)))) + val |= (-1U << (operand->bits - 1)) << 1; + + /* Double value if the operand is pc relative. */ + if (operand->flags & S390_OPERAND_PCREL) + val <<= 1; + + /* Length x in an instructions has real length x + 1. */ + if (operand->flags & S390_OPERAND_LENGTH) + val++; + return val; +} + +/* Print a S390 instruction. */ + +int +print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) +{ + bfd_byte buffer[6]; + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + unsigned int value; + int status, opsize, bufsize; + char separator; + + if (init_flag == 0) + init_disasm (info); + + /* The output looks better if we put 6 bytes on a line. */ + info->bytes_per_line = 6; + + /* Every S390 instruction is max 6 bytes long. */ + memset (buffer, 0, 6); + status = (*info->read_memory_func) (memaddr, buffer, 6, info); + if (status != 0) + { + for (bufsize = 0; bufsize < 6; bufsize++) + if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) + break; + if (bufsize <= 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + /* Opsize calculation looks strange but it works + 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, + 11xxxxxx -> 6 bytes. */ + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + status = opsize > bufsize; + } + else + { + bufsize = 6; + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + } + + if (status == 0) + { + /* Find the first match in the opcode table. */ + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; + (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); + opcode++) + { + const struct s390_operand *operand; + const unsigned char *opindex; + + /* Check architecture. */ + if (!(opcode->modes & current_arch_mask)) + continue; + /* Check signature of the opcode. */ + if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] + || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] + || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] + || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] + || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) + continue; + + /* The instruction is valid. */ + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "%s\t", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* Extract the operands. */ + separator = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + unsigned int value; + + operand = s390_operands + *opindex; + value = s390_extract_operand (buffer, operand); + + if ((operand->flags & S390_OPERAND_INDEX) && value == 0) + continue; + if ((operand->flags & S390_OPERAND_BASE) && + value == 0 && separator == '(') + { + separator = ','; + continue; + } + + if (separator) + (*info->fprintf_func) (info->stream, "%c", separator); + + if (operand->flags & S390_OPERAND_GPR) + (*info->fprintf_func) (info->stream, "%%r%i", value); + else if (operand->flags & S390_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%%f%i", value); + else if (operand->flags & S390_OPERAND_AR) + (*info->fprintf_func) (info->stream, "%%a%i", value); + else if (operand->flags & S390_OPERAND_CR) + (*info->fprintf_func) (info->stream, "%%c%i", value); + else if (operand->flags & S390_OPERAND_PCREL) + (*info->print_address_func) (memaddr + (int) value, info); + else if (operand->flags & S390_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%i", (int) value); + else + (*info->fprintf_func) (info->stream, "%u", value); + + if (operand->flags & S390_OPERAND_DISP) + { + separator = '('; + } + else if (operand->flags & S390_OPERAND_BASE) + { + (*info->fprintf_func) (info->stream, ")"); + separator = ','; + } + else + separator = ','; + } + + /* Found instruction, printed it, return its size. */ + return opsize; + } + /* No matching instruction found, fall through to hex print. */ + } + + if (bufsize >= 4) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + value = (value << 8) + (unsigned int) buffer[2]; + value = (value << 8) + (unsigned int) buffer[3]; + (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); + return 4; + } + else if (bufsize >= 2) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); + return 2; + } + else + { + value = (unsigned int) buffer[0]; + (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); + return 1; + } +} +/* s390-opc.c -- S390 opcode list + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of GDB, GAS, and the GNU binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include + +/* This file holds the S390 opcode table. The opcode table + includes almost all of the extended instruction mnemonics. This + permits the disassembler to use them, and simplifies the assembler + logic, at the cost of increasing the table size. The table is + strictly constant data, so the compiler should be able to put it in + the .text section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* The operands table. + The fields are bits, shift, insert, extract, flags. */ + +const struct s390_operand s390_operands[] = +{ +#define UNUSED 0 + { 0, 0, 0 }, /* Indicates the end of the operand list */ + +#define R_8 1 /* GPR starting at position 8 */ + { 4, 8, S390_OPERAND_GPR }, +#define R_12 2 /* GPR starting at position 12 */ + { 4, 12, S390_OPERAND_GPR }, +#define R_16 3 /* GPR starting at position 16 */ + { 4, 16, S390_OPERAND_GPR }, +#define R_20 4 /* GPR starting at position 20 */ + { 4, 20, S390_OPERAND_GPR }, +#define R_24 5 /* GPR starting at position 24 */ + { 4, 24, S390_OPERAND_GPR }, +#define R_28 6 /* GPR starting at position 28 */ + { 4, 28, S390_OPERAND_GPR }, +#define R_32 7 /* GPR starting at position 32 */ + { 4, 32, S390_OPERAND_GPR }, + +#define F_8 8 /* FPR starting at position 8 */ + { 4, 8, S390_OPERAND_FPR }, +#define F_12 9 /* FPR starting at position 12 */ + { 4, 12, S390_OPERAND_FPR }, +#define F_16 10 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_20 11 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_24 12 /* FPR starting at position 24 */ + { 4, 24, S390_OPERAND_FPR }, +#define F_28 13 /* FPR starting at position 28 */ + { 4, 28, S390_OPERAND_FPR }, +#define F_32 14 /* FPR starting at position 32 */ + { 4, 32, S390_OPERAND_FPR }, + +#define A_8 15 /* Access reg. starting at position 8 */ + { 4, 8, S390_OPERAND_AR }, +#define A_12 16 /* Access reg. starting at position 12 */ + { 4, 12, S390_OPERAND_AR }, +#define A_24 17 /* Access reg. starting at position 24 */ + { 4, 24, S390_OPERAND_AR }, +#define A_28 18 /* Access reg. starting at position 28 */ + { 4, 28, S390_OPERAND_AR }, + +#define C_8 19 /* Control reg. starting at position 8 */ + { 4, 8, S390_OPERAND_CR }, +#define C_12 20 /* Control reg. starting at position 12 */ + { 4, 12, S390_OPERAND_CR }, + +#define B_16 21 /* Base register starting at position 16 */ + { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR }, +#define B_32 22 /* Base register starting at position 32 */ + { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR }, + +#define X_12 23 /* Index register starting at position 12 */ + { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR }, + +#define D_20 24 /* Displacement starting at position 20 */ + { 12, 20, S390_OPERAND_DISP }, +#define D_36 25 /* Displacement starting at position 36 */ + { 12, 36, S390_OPERAND_DISP }, +#define D20_20 26 /* 20 bit displacement starting at 20 */ + { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED }, + +#define L4_8 27 /* 4 bit length starting at position 8 */ + { 4, 8, S390_OPERAND_LENGTH }, +#define L4_12 28 /* 4 bit length starting at position 12 */ + { 4, 12, S390_OPERAND_LENGTH }, +#define L8_8 29 /* 8 bit length starting at position 8 */ + { 8, 8, S390_OPERAND_LENGTH }, + +#define U4_8 30 /* 4 bit unsigned value starting at 8 */ + { 4, 8, 0 }, +#define U4_12 31 /* 4 bit unsigned value starting at 12 */ + { 4, 12, 0 }, +#define U4_16 32 /* 4 bit unsigned value starting at 16 */ + { 4, 16, 0 }, +#define U4_20 33 /* 4 bit unsigned value starting at 20 */ + { 4, 20, 0 }, +#define U8_8 34 /* 8 bit unsigned value starting at 8 */ + { 8, 8, 0 }, +#define U8_16 35 /* 8 bit unsigned value starting at 16 */ + { 8, 16, 0 }, +#define I16_16 36 /* 16 bit signed value starting at 16 */ + { 16, 16, S390_OPERAND_SIGNED }, +#define U16_16 37 /* 16 bit unsigned value starting at 16 */ + { 16, 16, 0 }, +#define J16_16 38 /* PC relative jump offset at 16 */ + { 16, 16, S390_OPERAND_PCREL }, +#define J32_16 39 /* PC relative long offset at 16 */ + { 32, 16, S390_OPERAND_PCREL }, +#define I32_16 40 /* 32 bit signed value starting at 16 */ + { 32, 16, S390_OPERAND_SIGNED }, +#define U32_16 41 /* 32 bit unsigned value starting at 16 */ + { 32, 16, 0 }, +#define M_16 42 /* 4 bit optional mask starting at 16 */ + { 4, 16, S390_OPERAND_OPTIONAL }, +#define RO_28 43 /* optional GPR starting at position 28 */ + { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) } + +}; + + +/* Macros used to form opcodes. */ + +/* 8/16/48 bit opcodes. */ +#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 } +#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \ + (x >> 16) & 255, (x >> 8) & 255, x & 255} + +/* The new format of the INSTR_x_y and MASK_x_y defines is based + on the following rules: + 1) the middle part of the definition (x in INSTR_x_y) is the official + names of the instruction format that you can find in the principals + of operation. + 2) the last part of the definition (y in INSTR_x_y) gives you an idea + which operands the binary represenation of the instruction has. + The meanings of the letters in y are: + a - access register + c - control register + d - displacement, 12 bit + f - floating pointer register + i - signed integer, 4, 8, 16 or 32 bit + l - length, 4 or 8 bit + p - pc relative + r - general purpose register + u - unsigned integer, 4, 8, 16 or 32 bit + m - mode field, 4 bit + 0 - operand skipped. + The order of the letters reflects the layout of the format in + storage and not the order of the paramaters of the instructions. + The use of the letters is not a 100% match with the PoP but it is + quite close. + + For example the instruction "mvo" is defined in the PoP as follows: + + MVO D1(L1,B1),D2(L2,B2) [SS] + + -------------------------------------- + | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 | + -------------------------------------- + 0 8 12 16 20 32 36 + + The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD. */ + +#define INSTR_E 2, { 0,0,0,0,0,0 } /* e.g. pr */ +#define INSTR_RIE_RRP 6, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxhg */ +#define INSTR_RIL_0P 6, { J32_16,0,0,0,0 } /* e.g. jg */ +#define INSTR_RIL_RP 6, { R_8,J32_16,0,0,0,0 } /* e.g. brasl */ +#define INSTR_RIL_UP 6, { U4_8,J32_16,0,0,0,0 } /* e.g. brcl */ +#define INSTR_RIL_RI 6, { R_8,I32_16,0,0,0,0 } /* e.g. afi */ +#define INSTR_RIL_RU 6, { R_8,U32_16,0,0,0,0 } /* e.g. alfi */ +#define INSTR_RI_0P 4, { J16_16,0,0,0,0,0 } /* e.g. j */ +#define INSTR_RI_RI 4, { R_8,I16_16,0,0,0,0 } /* e.g. ahi */ +#define INSTR_RI_RP 4, { R_8,J16_16,0,0,0,0 } /* e.g. brct */ +#define INSTR_RI_RU 4, { R_8,U16_16,0,0,0,0 } /* e.g. tml */ +#define INSTR_RI_UP 4, { U4_8,J16_16,0,0,0,0 } /* e.g. brc */ +#define INSTR_RRE_00 4, { 0,0,0,0,0,0 } /* e.g. palb */ +#define INSTR_RRE_0R 4, { R_28,0,0,0,0,0 } /* e.g. tb */ +#define INSTR_RRE_AA 4, { A_24,A_28,0,0,0,0 } /* e.g. cpya */ +#define INSTR_RRE_AR 4, { A_24,R_28,0,0,0,0 } /* e.g. sar */ +#define INSTR_RRE_F0 4, { F_24,0,0,0,0,0 } /* e.g. sqer */ +#define INSTR_RRE_FF 4, { F_24,F_28,0,0,0,0 } /* e.g. debr */ +#define INSTR_RRE_R0 4, { R_24,0,0,0,0,0 } /* e.g. ipm */ +#define INSTR_RRE_RA 4, { R_24,A_28,0,0,0,0 } /* e.g. ear */ +#define INSTR_RRE_RF 4, { R_24,F_28,0,0,0,0 } /* e.g. cefbr */ +#define INSTR_RRE_RR 4, { R_24,R_28,0,0,0,0 } /* e.g. lura */ +#define INSTR_RRE_FR 4, { F_24,R_28,0,0,0,0 } /* e.g. ldgr */ +/* Actually efpc and sfpc do not take an optional operand. + This is just a workaround for existing code e.g. glibc. */ +#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ +#define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ +#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +#define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ +#define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ +#define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ +#define INSTR_RRF_R0RR 4, { R_24,R_28,R_16,0,0,0 } /* e.g. idte */ +#define INSTR_RRF_U0FF 4, { F_24,U4_16,F_28,0,0,0 } /* e.g. fixr */ +#define INSTR_RRF_U0RF 4, { R_24,U4_16,F_28,0,0,0 } /* e.g. cfebr */ +#define INSTR_RRF_UUFF 4, { F_24,U4_16,F_28,U4_20,0,0 } /* e.g. fidtr */ +#define INSTR_RRF_0UFF 4, { F_24,F_28,U4_20,0,0,0 } /* e.g. ldetr */ +#define INSTR_RRF_FFFU 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. qadtr */ +#define INSTR_RRF_M0RR 4, { R_24,R_28,M_16,0,0,0 } /* e.g. sske */ +#define INSTR_RR_0R 2, { R_12, 0,0,0,0,0 } /* e.g. br */ +#define INSTR_RR_FF 2, { F_8,F_12,0,0,0,0 } /* e.g. adr */ +#define INSTR_RR_R0 2, { R_8, 0,0,0,0,0 } /* e.g. spm */ +#define INSTR_RR_RR 2, { R_8,R_12,0,0,0,0 } /* e.g. lr */ +#define INSTR_RR_U0 2, { U8_8, 0,0,0,0,0 } /* e.g. svc */ +#define INSTR_RR_UR 2, { U4_8,R_12,0,0,0,0 } /* e.g. bcr */ +#define INSTR_RRR_F0FF 4, { F_24,F_28,F_16,0,0,0 } /* e.g. ddtr */ +#define INSTR_RSE_RRRD 6, { R_8,R_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_CCRD 6, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_RURD 6, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSL_R0RD 6, { R_8,D_20,B_16,0,0,0 } /* e.g. tp */ +#define INSTR_RSI_RRP 4, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxh */ +#define INSTR_RSY_RRRD 6, { R_8,R_12,D20_20,B_16,0,0 } /* e.g. stmy */ +#define INSTR_RSY_RURD 6, { R_8,U4_12,D20_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSY_AARD 6, { A_8,A_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RSY_CCRD 6, { C_8,C_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RS_AARD 4, { A_8,A_12,D_20,B_16,0,0 } /* e.g. lam */ +#define INSTR_RS_CCRD 4, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lctl */ +#define INSTR_RS_R0RD 4, { R_8,D_20,B_16,0,0,0 } /* e.g. sll */ +#define INSTR_RS_RRRD 4, { R_8,R_12,D_20,B_16,0,0 } /* e.g. cs */ +#define INSTR_RS_RURD 4, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icm */ +#define INSTR_RXE_FRRD 6, { F_8,D_20,X_12,B_16,0,0 } /* e.g. axbr */ +#define INSTR_RXE_RRRD 6, { R_8,D_20,X_12,B_16,0,0 } /* e.g. lg */ +#define INSTR_RXF_FRRDF 6, { F_32,F_8,D_20,X_12,B_16,0 } /* e.g. madb */ +#define INSTR_RXF_RRRDR 6, { R_32,R_8,D_20,X_12,B_16,0 } /* e.g. .insn */ +#define INSTR_RXY_RRRD 6, { R_8,D20_20,X_12,B_16,0,0 } /* e.g. ly */ +#define INSTR_RXY_FRRD 6, { F_8,D20_20,X_12,B_16,0,0 } /* e.g. ley */ +#define INSTR_RX_0RRD 4, { D_20,X_12,B_16,0,0,0 } /* e.g. be */ +#define INSTR_RX_FRRD 4, { F_8,D_20,X_12,B_16,0,0 } /* e.g. ae */ +#define INSTR_RX_RRRD 4, { R_8,D_20,X_12,B_16,0,0 } /* e.g. l */ +#define INSTR_RX_URRD 4, { U4_8,D_20,X_12,B_16,0,0 } /* e.g. bc */ +#define INSTR_SI_URD 4, { D_20,B_16,U8_8,0,0,0 } /* e.g. cli */ +#define INSTR_SIY_URD 6, { D20_20,B_16,U8_8,0,0,0 } /* e.g. tmy */ +#define INSTR_SSE_RDRD 6, { D_20,B_16,D_36,B_32,0,0 } /* e.g. mvsdk */ +#define INSTR_SS_L0RDRD 6, { D_20,L8_8,B_16,D_36,B_32,0 } /* e.g. mvc */ +#define INSTR_SS_L2RDRD 6, { D_20,B_16,D_36,L8_8,B_32,0 } /* e.g. pka */ +#define INSTR_SS_LIRDRD 6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp */ +#define INSTR_SS_LLRDRD 6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack */ +#define INSTR_SS_RRRDRD 6, { D_20,R_8,B_16,D_36,B_32,R_12 } /* e.g. mvck */ +#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 } /* e.g. plo */ +#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 } /* e.g. lmd */ +#define INSTR_S_00 4, { 0,0,0,0,0,0 } /* e.g. hsch */ +#define INSTR_S_RD 4, { D_20,B_16,0,0,0,0 } /* e.g. lpsw */ +#define INSTR_SSF_RRDRD 6, { D_20,B_16,D_36,B_32,R_8,0 } /* e.g. mvcos */ + +#define MASK_E { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIE_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RIL_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRE_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_RRE_0R { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } +#define MASK_RRE_AA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_AR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_F0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_FF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_R0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_RA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_FR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR_OPT { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF2 { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_FUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_RURR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_R0RR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0RF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_UUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_0UFF { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } +#define MASK_RRF_FFFU { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_M0RR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RR_0R { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_FF { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_R0 { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_RR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_U0 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_UR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRR_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RSE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSL_R0RD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSI_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_R0RD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RSY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_FRRDF { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_RRRDR { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RX_0RRD { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SI_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SIY_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_SSE_RDRD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L0RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L2RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LIRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LLRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD2 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD3 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_S_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_S_RD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } + +/* The opcode formats table (blueprints for .insn pseudo mnemonic). */ + +const struct s390_opcode s390_opformats[] = + { + { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 }, + { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 }, + { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0 }, + { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0 }, + { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0 }, + { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0 }, + { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0 }, + { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0 }, + { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0 }, + { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0 }, + { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0 }, + { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3 }, + { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0 }, + { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0 }, + { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR,3, 0 }, + { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3 }, + { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0 }, + { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0 }, + { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3 }, + { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD,3, 0 }, + { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0 }, + { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 }, +}; + +const int s390_num_opformats = + sizeof (s390_opformats) / sizeof (s390_opformats[0]); + +/* The opcode table. This file was generated by s390-mkopc. + + The format of the opcode table is: + + NAME OPCODE MASK OPERANDS + + Name is the name of the instruction. + OPCODE is the instruction opcode. + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + OPERANDS is the list of operands. + + The disassembler reads the table in order and prints the first + instruction which matches. */ + +const struct s390_opcode s390_opcodes[] = + { + { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0}, + { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2}, + { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0}, + { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, + { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0}, + { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, + { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, + { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, + { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2}, + { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4}, + { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2}, + { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3}, + { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3}, + { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5}, + { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5}, + { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2}, + { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2}, + { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0}, + { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0}, + { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0}, + { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0}, + { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2}, + { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0}, + { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0}, + { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0}, + { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0}, + { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0}, + { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0}, + { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2}, + { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2}, + { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2}, + { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2}, + { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5}, + { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, + { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, + { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0} +}; + +const int s390_num_opcodes = + sizeof (s390_opcodes) / sizeof (s390_opcodes[0]); diff --git a/qemu/qemu-git/.svn/text-base/s390.ld.svn-base b/qemu/qemu-git/.svn/text-base/s390.ld.svn-base new file mode 100644 index 0000000..a9c5370 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/s390.ld.svn-base @@ -0,0 +1,201 @@ +OUTPUT_FORMAT("elf32-s390", "elf32-s390", + "elf32-s390") +OUTPUT_ARCH(s390:31-bit) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x07070707 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x07070707 + .fini : + { + KEEP (*(.fini)) + } =0x07070707 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/qemu/qemu-git/.svn/text-base/sh4-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/sh4-dis.c.svn-base new file mode 100644 index 0000000..41fd866 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/sh4-dis.c.svn-base @@ -0,0 +1,2083 @@ +/* Disassemble SH instructions. + Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include +#include "dis-asm.h" + +#define DEFINE_TABLE + +typedef enum + { + HEX_0, + HEX_1, + HEX_2, + HEX_3, + HEX_4, + HEX_5, + HEX_6, + HEX_7, + HEX_8, + HEX_9, + HEX_A, + HEX_B, + HEX_C, + HEX_D, + HEX_E, + HEX_F, + HEX_XX00, + HEX_00YY, + REG_N, + REG_N_D, /* nnn0 */ + REG_N_B01, /* nn01 */ + REG_M, + SDT_REG_N, + REG_NM, + REG_B, + BRANCH_12, + BRANCH_8, + IMM0_4, + IMM0_4BY2, + IMM0_4BY4, + IMM1_4, + IMM1_4BY2, + IMM1_4BY4, + PCRELIMM_8BY2, + PCRELIMM_8BY4, + IMM0_8, + IMM0_8BY2, + IMM0_8BY4, + IMM1_8, + IMM1_8BY2, + IMM1_8BY4, + PPI, + NOPX, + NOPY, + MOVX, + MOVY, + MOVX_NOPY, + MOVY_NOPX, + PSH, + PMUL, + PPI3, + PPI3NC, + PDC, + PPIC, + REPEAT, + IMM0_3c, /* xxxx 0iii */ + IMM0_3s, /* xxxx 1iii */ + IMM0_3Uc, /* 0iii xxxx */ + IMM0_3Us, /* 1iii xxxx */ + IMM0_20_4, + IMM0_20, /* follows IMM0_20_4 */ + IMM0_20BY8, /* follows IMM0_20_4 */ + DISP0_12, + DISP0_12BY2, + DISP0_12BY4, + DISP0_12BY8, + DISP1_12, + DISP1_12BY2, + DISP1_12BY4, + DISP1_12BY8 + } +sh_nibble_type; + +typedef enum + { + A_END, + A_BDISP12, + A_BDISP8, + A_DEC_M, + A_DEC_N, + A_DISP_GBR, + A_PC, + A_DISP_PC, + A_DISP_PC_ABS, + A_DISP_REG_M, + A_DISP_REG_N, + A_GBR, + A_IMM, + A_INC_M, + A_INC_N, + A_IND_M, + A_IND_N, + A_IND_R0_REG_M, + A_IND_R0_REG_N, + A_MACH, + A_MACL, + A_PR, + A_R0, + A_R0_GBR, + A_REG_M, + A_REG_N, + A_REG_B, + A_SR, + A_VBR, + A_TBR, + A_DISP_TBR, + A_DISP2_TBR, + A_DEC_R15, + A_INC_R15, + A_MOD, + A_RE, + A_RS, + A_DSR, + DSP_REG_M, + DSP_REG_N, + DSP_REG_X, + DSP_REG_Y, + DSP_REG_E, + DSP_REG_F, + DSP_REG_G, + DSP_REG_A_M, + DSP_REG_AX, + DSP_REG_XY, + DSP_REG_AY, + DSP_REG_YX, + AX_INC_N, + AY_INC_N, + AXY_INC_N, + AYX_INC_N, + AX_IND_N, + AY_IND_N, + AXY_IND_N, + AYX_IND_N, + AX_PMOD_N, + AXY_PMOD_N, + AY_PMOD_N, + AYX_PMOD_N, + AS_DEC_N, + AS_INC_N, + AS_IND_N, + AS_PMOD_N, + A_A0, + A_X0, + A_X1, + A_Y0, + A_Y1, + A_SSR, + A_SPC, + A_SGR, + A_DBR, + F_REG_N, + F_REG_M, + D_REG_N, + D_REG_M, + X_REG_N, /* Only used for argument parsing. */ + X_REG_M, /* Only used for argument parsing. */ + DX_REG_N, + DX_REG_M, + V_REG_N, + V_REG_M, + XMTRX_M4, + F_FR0, + FPUL_N, + FPUL_M, + FPSCR_N, + FPSCR_M + } +sh_arg_type; + +typedef enum + { + A_A1_NUM = 5, + A_A0_NUM = 7, + A_X0_NUM, A_X1_NUM, A_Y0_NUM, A_Y1_NUM, + A_M0_NUM, A_A1G_NUM, A_M1_NUM, A_A0G_NUM + } +sh_dsp_reg_nums; + +#define arch_sh1_base 0x0001 +#define arch_sh2_base 0x0002 +#define arch_sh3_base 0x0004 +#define arch_sh4_base 0x0008 +#define arch_sh4a_base 0x0010 +#define arch_sh2a_base 0x0020 + +/* This is an annotation on instruction types, but we abuse the arch + field in instructions to denote it. */ +#define arch_op32 0x00100000 /* This is a 32-bit opcode. */ + +#define arch_sh_no_mmu 0x04000000 +#define arch_sh_has_mmu 0x08000000 +#define arch_sh_no_co 0x10000000 /* neither FPU nor DSP co-processor */ +#define arch_sh_sp_fpu 0x20000000 /* single precision FPU */ +#define arch_sh_dp_fpu 0x40000000 /* double precision FPU */ +#define arch_sh_has_dsp 0x80000000 + + +#define arch_sh_base_mask 0x0000003f +#define arch_opann_mask 0x00100000 +#define arch_sh_mmu_mask 0x0c000000 +#define arch_sh_co_mask 0xf0000000 + + +#define arch_sh1 (arch_sh1_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2 (arch_sh2_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2a (arch_sh2a_base|arch_sh_no_mmu|arch_sh_dp_fpu) +#define arch_sh2a_nofpu (arch_sh2a_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2e (arch_sh2_base|arch_sh2a_base|arch_sh_no_mmu|arch_sh_sp_fpu) +#define arch_sh_dsp (arch_sh2_base|arch_sh_no_mmu|arch_sh_has_dsp) +#define arch_sh3_nommu (arch_sh3_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh3 (arch_sh3_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh3e (arch_sh3_base|arch_sh_has_mmu|arch_sh_sp_fpu) +#define arch_sh3_dsp (arch_sh3_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4 (arch_sh4_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4a (arch_sh4a_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4al_dsp (arch_sh4a_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4_nofpu (arch_sh4_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4a_nofpu (arch_sh4a_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4_nommu_nofpu (arch_sh4_base|arch_sh_no_mmu|arch_sh_no_co) + +#define SH_MERGE_ARCH_SET(SET1, SET2) ((SET1) & (SET2)) +#define SH_VALID_BASE_ARCH_SET(SET) (((SET) & arch_sh_base_mask) != 0) +#define SH_VALID_MMU_ARCH_SET(SET) (((SET) & arch_sh_mmu_mask) != 0) +#define SH_VALID_CO_ARCH_SET(SET) (((SET) & arch_sh_co_mask) != 0) +#define SH_VALID_ARCH_SET(SET) \ + (SH_VALID_BASE_ARCH_SET (SET) \ + && SH_VALID_MMU_ARCH_SET (SET) \ + && SH_VALID_CO_ARCH_SET (SET)) +#define SH_MERGE_ARCH_SET_VALID(SET1, SET2) \ + SH_VALID_ARCH_SET (SH_MERGE_ARCH_SET (SET1, SET2)) + +#define SH_ARCH_SET_HAS_FPU(SET) \ + (((SET) & (arch_sh_sp_fpu | arch_sh_dp_fpu)) != 0) +#define SH_ARCH_SET_HAS_DSP(SET) \ + (((SET) & arch_sh_has_dsp) != 0) + +/* This is returned from the functions below when an error occurs + (in addition to a call to BFD_FAIL). The value should allow + the tools to continue to function in most cases - there may + be some confusion between DSP and FPU etc. */ +#define SH_ARCH_UNKNOWN_ARCH 0xffffffff + +/* These are defined in bfd/cpu-sh.c . */ +unsigned int sh_get_arch_from_bfd_mach (unsigned long mach); +unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach); +unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set); +/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */ + +/* Below are the 'architecture sets'. + They describe the following inheritance graph: + + SH1 + | + SH2 + .------------'|`--------------------. + / | \ +SH-DSP SH3-nommu SH2E + | |`--------. | + | | \ | + | SH3 SH4-nommu-nofpu | + | | | | + | .------------'|`----------+---------. | + |/ / \| + | | .-------' | + | |/ | +SH3-dsp SH4-nofpu SH3E + | |`--------------------. | + | | \| + | SH4A-nofpu SH4 + | .------------' `--------------------. | + |/ \| +SH4AL-dsp SH4A + +*/ + +/* Central branches */ +#define arch_sh1_up (arch_sh1 | arch_sh2_up) +#define arch_sh2_up (arch_sh2 | arch_sh2e_up | arch_sh2a_nofpu_up | arch_sh3_nommu_up | arch_sh_dsp_up) +#define arch_sh3_nommu_up (arch_sh3_nommu | arch_sh3_up | arch_sh4_nommu_nofpu_up) +#define arch_sh3_up (arch_sh3 | arch_sh3e_up | arch_sh3_dsp_up | arch_sh4_nofp_up) +#define arch_sh4_nommu_nofpu_up (arch_sh4_nommu_nofpu | arch_sh4_nofp_up) +#define arch_sh4_nofp_up (arch_sh4_nofpu | arch_sh4_up | arch_sh4a_nofp_up) +#define arch_sh4a_nofp_up (arch_sh4a_nofpu | arch_sh4a_up | arch_sh4al_dsp_up) + +/* Right branch */ +#define arch_sh2e_up (arch_sh2e | arch_sh2a_up | arch_sh3e_up) +#define arch_sh3e_up (arch_sh3e | arch_sh4_up) +#define arch_sh4_up (arch_sh4 | arch_sh4a_up) +#define arch_sh4a_up (arch_sh4a) + +/* Left branch */ +#define arch_sh_dsp_up (arch_sh_dsp | arch_sh3_dsp_up) +#define arch_sh3_dsp_up (arch_sh3_dsp | arch_sh4al_dsp_up) +#define arch_sh4al_dsp_up (arch_sh4al_dsp) + +/* SH 2a branched off SH2e, adding a lot but not all of SH4 and SH4a. */ +#define arch_sh2a_up (arch_sh2a) +#define arch_sh2a_nofpu_up (arch_sh2a_nofpu | arch_sh2a_up) + + +typedef struct +{ + const char *name; + sh_arg_type arg[4]; + sh_nibble_type nibbles[9]; + unsigned int arch; +} sh_opcode_info; + +#ifdef DEFINE_TABLE + +const sh_opcode_info sh_table[] = + { +/* 0111nnnni8*1.... add #, */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1100 add , */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0011nnnnmmmm1110 addc ,*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0011nnnnmmmm1111 addv ,*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 11001001i8*1.... and #,R0 */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1001 and , */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 11001101i8*1.... and.b #,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM0_8}, arch_sh1_up}, + +/* 1010i12......... bra */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}, arch_sh1_up}, + +/* 1011i12......... bsr */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}, arch_sh1_up}, + +/* 10001001i8p1.... bt */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}, arch_sh1_up}, + +/* 10001011i8p1.... bf */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}, arch_sh1_up}, + +/* 10001101i8p1.... bt.s */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001101i8p1.... bt/s */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf.s */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf/s */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 0000000010001000 clrdmxy */{"clrdmxy",{0},{HEX_0,HEX_0,HEX_8,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000000101000 clrmac */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0000000001001000 clrs */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}, arch_sh1_up}, + +/* 0000000000001000 clrt */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}, arch_sh1_up}, + +/* 10001000i8*1.... cmp/eq #,R0 */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm0000 cmp/eq ,*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 0011nnnnmmmm0011 cmp/ge ,*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0011nnnnmmmm0111 cmp/gt ,*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0011nnnnmmmm0110 cmp/hi ,*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0011nnnnmmmm0010 cmp/hs ,*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010101 cmp/pl */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00010001 cmp/pz */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}, arch_sh1_up}, + +/* 0010nnnnmmmm1100 cmp/str ,*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0010nnnnmmmm0111 div0s ,*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0000000000011001 div0u */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0011nnnnmmmm0100 div1 ,*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm1110 exts.b ,*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1111 exts.w ,*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0110nnnnmmmm1100 extu.b ,*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm1101 extu.w ,*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnn11100011 icbi @ */{"icbi",{A_IND_N},{HEX_0,REG_N,HEX_E,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00101011 jmp @ */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001011 jsr @ */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001110 ldc ,SR */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00011110 ldc ,GBR */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00111010 ldc ,SGR */{"ldc",{A_REG_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100mmmm01001010 ldc ,TBR */{"ldc",{A_REG_M,A_TBR},{HEX_4,REG_M,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00101110 ldc ,VBR */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}, arch_sh1_up}, + +/* 0100nnnn01011110 ldc ,MOD */{"ldc",{A_REG_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01111110 ldc ,RE */{"ldc",{A_REG_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01101110 ldc ,RS */{"ldc",{A_REG_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn00111110 ldc ,SSR */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn01001110 ldc ,SPC */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn11111010 ldc ,DBR */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx1110 ldc ,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn00000111 ldc.l @+,SR */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010111 ldc.l @+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00100111 ldc.l @+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00110110 ldc.l @+,SGR */{"ldc.l",{A_INC_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn01010111 ldc.l @+,MOD */{"ldc.l",{A_INC_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01110111 ldc.l @+,RE */{"ldc.l",{A_INC_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01100111 ldc.l @+,RS */{"ldc.l",{A_INC_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn00110111 ldc.l @+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn01000111 ldc.l @+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn11110110 ldc.l @+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0111 ldc.l ,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}, arch_sh3_nommu_up}, + +/* 0100mmmm00110100 ldrc */{"ldrc",{A_REG_M},{HEX_4,REG_M,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* 10001010i8*1.... ldrc # */{"ldrc",{A_IMM},{HEX_8,HEX_A,IMM0_8}, arch_sh4al_dsp_up}, + +/* 10001110i8p2.... ldre @(,PC) */{"ldre",{A_DISP_PC},{HEX_8,HEX_E,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 10001100i8p2.... ldrs @(,PC) */{"ldrs",{A_DISP_PC},{HEX_8,HEX_C,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 0100nnnn00001010 lds ,MACH */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00011010 lds ,MACL */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00101010 lds ,PR */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0100nnnn01101010 lds ,DSR */{"lds",{A_REG_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01111010 lds ,A0 */{"lds",{A_REG_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10001010 lds ,X0 */{"lds",{A_REG_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10011010 lds ,X1 */{"lds",{A_REG_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10101010 lds ,Y0 */{"lds",{A_REG_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10111010 lds ,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00010110 lds.l @+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00100110 lds.l @+,PR */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}, arch_sh1_up}, + +/* 0100nnnn01100110 lds.l @+,DSR */{"lds.l",{A_INC_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 lds.l @+,A0 */{"lds.l",{A_INC_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 lds.l @+,X0 */{"lds.l",{A_INC_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 lds.l @+,X1 */{"lds.l",{A_INC_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 lds.l @+,Y0 */{"lds.l",{A_INC_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 lds.l @+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up}, + +/* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up}, + +/* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up}, + +/* 0100nnnnmmmm1111 mac.w @+,@+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 1110nnnni8*1.... mov #, */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0110nnnnmmmm0011 mov , */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0000nnnnmmmm0100 mov.b ,@(R0,)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0100 mov.b ,@-*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0000 mov.b ,@*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000100mmmmi4*1 mov.b @(,),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM0_4}, arch_sh1_up}, + +/* 11000100i8*1.... mov.b @(,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM0_8}, arch_sh1_up}, + +/* 0000nnnnmmmm1100 mov.b @(R0,),*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm0100 mov.b @+,*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm0000 mov.b @,*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000000mmmmi4*1 mov.b R0,@(,)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM1_4}, arch_sh1_up}, + +/* 11000000i8*1.... mov.b R0,@(,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM1_8}, arch_sh1_up}, + +/* 0100nnnn10001011 mov.b R0,@+ */{"mov.b",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_8,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.b @-,R0 */{"mov.b",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_C,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0000dddddddddddd mov.b ,@(,) */ +{"mov.b",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0100dddddddddddd mov.b @(,), */ +{"mov.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_4,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0001nnnnmmmmi4*4 mov.l ,@(,)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM1_4BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm0110 mov.l ,@(R0,)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0110 mov.l ,@-*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0010 mov.l ,@*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0101nnnnmmmmi4*4 mov.l @(,),*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM0_4BY4}, arch_sh1_up}, + +/* 11000110i8*4.... mov.l @(,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM0_8BY4}, arch_sh1_up}, + +/* 1101nnnni8p4.... mov.l @(,PC),*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm1110 mov.l @(R0,),*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm0110 mov.l @+,*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0110nnnnmmmm0010 mov.l @,*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 11000010i8*4.... mov.l R0,@(,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM1_8BY4}, arch_sh1_up}, + +/* 0100nnnn10101011 mov.l R0,@+ */{"mov.l",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_A,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.l @-,R0 */{"mov.l",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0010dddddddddddd mov.l ,@(,) */ +{"mov.l",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_2,DISP1_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0110dddddddddddd mov.l @(,), */ +{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_6,DISP0_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnnmmmm0101 mov.w ,@(R0,)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0101 mov.w ,@-*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0001 mov.w ,@*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000101mmmmi4*2 mov.w @(,),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM0_4BY2}, arch_sh1_up}, + +/* 11000101i8*2.... mov.w @(,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM0_8BY2}, arch_sh1_up}, + +/* 1001nnnni8p2.... mov.w @(,PC),*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}, arch_sh1_up}, + +/* 0000nnnnmmmm1101 mov.w @(R0,),*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0110nnnnmmmm0101 mov.w @+,*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0110nnnnmmmm0001 mov.w @,*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000001mmmmi4*2 mov.w R0,@(,)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM1_4BY2}, arch_sh1_up}, + +/* 11000001i8*2.... mov.w R0,@(,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM1_8BY2}, arch_sh1_up}, + +/* 0100nnnn10011011 mov.w R0,@+ */{"mov.w",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_9,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11011011 mov.w @-,R0 */{"mov.w",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_D,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0001dddddddddddd mov.w ,@(,) */ +{"mov.w",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_1,DISP1_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0101dddddddddddd mov.w @(,), */ +{"mov.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_5,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 11000111i8p4.... mova @(,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}, arch_sh1_up}, +/* 0000nnnn11000011 movca.l R0,@ */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn01110011 movco.l r0,@ */{"movco.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_7,HEX_3}, arch_sh4a_nofp_up}, +/* 0000mmmm01100011 movli.l @,r0 */{"movli.l",{A_IND_M,A_R0},{HEX_0,REG_M,HEX_6,HEX_3}, arch_sh4a_nofp_up}, + +/* 0000nnnn00101001 movt */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100mmmm10101001 movua.l @,r0 */{"movua.l",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_A,HEX_9}, arch_sh4a_nofp_up}, +/* 0100mmmm11101001 movua.l @+,r0 */{"movua.l",{A_INC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_9}, arch_sh4a_nofp_up}, + +/* 0010nnnnmmmm1111 muls.w ,*/{"muls.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, +/* 0010nnnnmmmm1111 muls ,*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh2_up}, + +/* 0010nnnnmmmm1110 mulu.w ,*/{"mulu.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, +/* 0010nnnnmmmm1110 mulu ,*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1011 neg , */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1010 negc ,*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0000000000001001 nop */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0110nnnnmmmm0111 not , */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}, arch_sh1_up}, +/* 0000nnnn10010011 ocbi @ */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10100011 ocbp @ */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10110011 ocbwb @ */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}, arch_sh4_nommu_nofpu_up}, + + +/* 11001011i8*1.... or #,R0 */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1011 or , */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 11001111i8*1.... or.b #,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM0_8}, arch_sh1_up}, + +/* 0000nnnn10000011 pref @ */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}, arch_sh4_nommu_nofpu_up | arch_sh2a_nofpu_up}, + +/* 0000nnnn11010011 prefi @ */{"prefi",{A_IND_N},{HEX_0,REG_N,HEX_D,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00100100 rotcl */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00100101 rotcr */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00000100 rotl */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00000101 rotr */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}, arch_sh1_up}, + +/* 0000000000101011 rte */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0000000000001011 rts */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0000000010011000 setdmx */{"setdmx",{0},{HEX_0,HEX_0,HEX_9,HEX_8}, arch_sh4al_dsp_up}, +/* 0000000011001000 setdmy */{"setdmy",{0},{HEX_0,HEX_0,HEX_C,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000001011000 sets */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}, arch_sh1_up}, +/* 0000000000011000 sett */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00010100 setrc */{"setrc",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* 10000010i8*1.... setrc # */{"setrc",{A_IMM},{HEX_8,HEX_2,IMM0_8}, arch_sh_dsp_up}, + +/* repeat start end */{"repeat",{A_DISP_PC,A_DISP_PC,A_REG_N},{REPEAT,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* repeat start end # */{"repeat",{A_DISP_PC,A_DISP_PC,A_IMM},{REPEAT,HEX_2,IMM0_8,HEX_8}, arch_sh_dsp_up}, + +/* 0100nnnnmmmm1100 shad ,*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnnmmmm1101 shld ,*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnn00100000 shal */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00100001 shar */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00000000 shll */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00101000 shll16 */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00001000 shll2 */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00011000 shll8 */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00000001 shlr */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00101001 shlr16 */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00001001 shlr2 */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00011001 shlr8 */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0000000000011011 sleep */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}, arch_sh1_up}, + +/* 0000nnnn00000010 stc SR, */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00010010 stc GBR, */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00100010 stc VBR, */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0000nnnn01010010 stc MOD, */{"stc",{A_MOD,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01110010 stc RE, */{"stc",{A_RE,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01100010 stc RS, */{"stc",{A_RS,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn00110010 stc SSR, */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01000010 stc SPC, */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn00111010 stc SGR, */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn11111010 stc DBR, */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn1xxx0010 stc Rn_BANK, */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01001010 stc TBR, */ {"stc",{A_TBR,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00000011 stc.l SR,@- */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00100011 stc.l VBR,@- */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}, arch_sh1_up}, + +/* 0100nnnn01010011 stc.l MOD,@- */{"stc.l",{A_MOD,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01110011 stc.l RE,@- */{"stc.l",{A_RE,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01100011 stc.l RS,@- */{"stc.l",{A_RS,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn00110011 stc.l SSR,@- */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn01000011 stc.l SPC,@- */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn00010011 stc.l GBR,@- */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00110010 stc.l SGR,@- */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn11110010 stc.l DBR,@- */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_F,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0011 stc.l Rn_BANK,@- */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}, arch_sh3_nommu_up}, + +/* 0000nnnn00001010 sts MACH, */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00011010 sts MACL, */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00101010 sts PR, */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0000nnnn01101010 sts DSR, */{"sts",{A_DSR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01111010 sts A0, */{"sts",{A_A0,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10001010 sts X0, */{"sts",{A_X0,A_REG_N},{HEX_0,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10011010 sts X1, */{"sts",{A_X1,A_REG_N},{HEX_0,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10101010 sts Y0, */{"sts",{A_Y0,A_REG_N},{HEX_0,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10111010 sts Y1, */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010010 sts.l MACL,@-*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00100010 sts.l PR,@- */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0100nnnn01100110 sts.l DSR,@- */{"sts.l",{A_DSR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 sts.l A0,@- */{"sts.l",{A_A0,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 sts.l X0,@- */{"sts.l",{A_X0,A_DEC_N},{HEX_4,REG_N,HEX_8,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 sts.l X1,@- */{"sts.l",{A_X1,A_DEC_N},{HEX_4,REG_N,HEX_9,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 sts.l Y0,@- */{"sts.l",{A_Y0,A_DEC_N},{HEX_4,REG_N,HEX_A,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 sts.l Y1,@- */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up}, + +/* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up}, + +/* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1010 subc ,*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0011nnnnmmmm1011 subv ,*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1000 swap.b ,*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0110nnnnmmmm1001 swap.w ,*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 0000000010101011 synco */{"synco",{0},{HEX_0,HEX_0,HEX_A,HEX_B}, arch_sh4a_nofp_up}, + +/* 0100nnnn00011011 tas.b @ */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}, arch_sh1_up}, + +/* 11000011i8*1.... trapa # */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM0_8}, arch_sh1_up}, + +/* 11001000i8*1.... tst #,R0 */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1000 tst , */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 11001100i8*1.... tst.b #,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM0_8}, arch_sh1_up}, + +/* 11001010i8*1.... xor #,R0 */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1010 xor , */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 11001110i8*1.... xor.b #,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1101 xtrct ,*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010000 dt */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}, arch_sh2_up}, + +/* 0011nnnnmmmm1101 dmuls.l ,*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}, arch_sh2_up}, + +/* 0011nnnnmmmm0101 dmulu.l ,*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}, arch_sh2_up}, + +/* 0000nnnnmmmm1111 mac.l @+,@+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}, arch_sh2_up}, + +/* 0000nnnn00100011 braf */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}, arch_sh2_up}, + +/* 0000nnnn00000011 bsrf */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}, arch_sh2_up}, + +/* 111101nnmmmm0000 movs.w @-, */ {"movs.w",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_0}, arch_sh_dsp_up}, + +/* 111101nnmmmm0001 movs.w @, */ {"movs.w",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_4}, arch_sh_dsp_up}, + +/* 111101nnmmmm0010 movs.w @+, */ {"movs.w",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_8}, arch_sh_dsp_up}, + +/* 111101nnmmmm0011 movs.w @+r8, */ {"movs.w",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_C}, arch_sh_dsp_up}, + +/* 111101nnmmmm0100 movs.w ,@- */ {"movs.w",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_1}, arch_sh_dsp_up}, + +/* 111101nnmmmm0101 movs.w ,@ */ {"movs.w",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_5}, arch_sh_dsp_up}, + +/* 111101nnmmmm0110 movs.w ,@+ */ {"movs.w",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_9}, arch_sh_dsp_up}, + +/* 111101nnmmmm0111 movs.w ,@+r8 */ {"movs.w",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_D}, arch_sh_dsp_up}, + +/* 111101nnmmmm1000 movs.l @-, */ {"movs.l",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_2}, arch_sh_dsp_up}, + +/* 111101nnmmmm1001 movs.l @, */ {"movs.l",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_6}, arch_sh_dsp_up}, + +/* 111101nnmmmm1010 movs.l @+, */ {"movs.l",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_A}, arch_sh_dsp_up}, + +/* 111101nnmmmm1011 movs.l @+r8, */ {"movs.l",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_E}, arch_sh_dsp_up}, + +/* 111101nnmmmm1100 movs.l ,@- */ {"movs.l",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_3}, arch_sh_dsp_up}, + +/* 111101nnmmmm1101 movs.l ,@ */ {"movs.l",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_7}, arch_sh_dsp_up}, + +/* 111101nnmmmm1110 movs.l ,@+ */ {"movs.l",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_B}, arch_sh_dsp_up}, + +/* 111101nnmmmm1111 movs.l ,@+r8 */ {"movs.l",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_F}, arch_sh_dsp_up}, + +/* 0*0*0*00** nopx */ {"nopx",{0},{PPI,NOPX}, arch_sh_dsp_up}, +/* *0*0*0**00 nopy */ {"nopy",{0},{PPI,NOPY}, arch_sh_dsp_up}, +/* n*m*0*01** movx.w @, */ {"movx.w",{AX_IND_N,DSP_REG_X},{PPI,MOVX,HEX_1}, arch_sh_dsp_up}, +/* n*m*0*10** movx.w @+, */ {"movx.w",{AX_INC_N,DSP_REG_X},{PPI,MOVX,HEX_2}, arch_sh_dsp_up}, +/* n*m*0*11** movx.w @+r8, */ {"movx.w",{AX_PMOD_N,DSP_REG_X},{PPI,MOVX,HEX_3}, arch_sh_dsp_up}, +/* n*m*1*01** movx.w ,@ */ {"movx.w",{DSP_REG_A_M,AX_IND_N},{PPI,MOVX,HEX_9}, arch_sh_dsp_up}, +/* n*m*1*10** movx.w ,@+ */ {"movx.w",{DSP_REG_A_M,AX_INC_N},{PPI,MOVX,HEX_A}, arch_sh_dsp_up}, +/* n*m*1*11** movx.w ,@+r8 */ {"movx.w",{DSP_REG_A_M,AX_PMOD_N},{PPI,MOVX,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000100 movx.w @, */ {"movx.w",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm001000 movx.w @+, */{"movx.w",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm001100 movx.w @+r8, */{"movx.w",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm100100 movx.w ,@ */ {"movx.w",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_2,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm101000 movx.w ,@+ */{"movx.w",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_2,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm101100 movx.w ,@+r8 */{"movx.w",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_2,HEX_C}, arch_sh4al_dsp_up}, + +/* nnmm010100 movx.l @, */ {"movx.l",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm011000 movx.l @+, */{"movx.l",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm011100 movx.l @+r8, */{"movx.l",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm110100 movx.l ,@ */ {"movx.l",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm111000 movx.l ,@+ */{"movx.l",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_3,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm111100 movx.l ,@+r8 */{"movx.l",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_3,HEX_C}, arch_sh4al_dsp_up}, + +/* *n*m*0**01 movy.w @, */ {"movy.w",{AY_IND_N,DSP_REG_Y},{PPI,MOVY,HEX_1}, arch_sh_dsp_up}, +/* *n*m*0**10 movy.w @+, */ {"movy.w",{AY_INC_N,DSP_REG_Y},{PPI,MOVY,HEX_2}, arch_sh_dsp_up}, +/* *n*m*0**11 movy.w @+r9, */ {"movy.w",{AY_PMOD_N,DSP_REG_Y},{PPI,MOVY,HEX_3}, arch_sh_dsp_up}, +/* *n*m*1**01 movy.w ,@ */ {"movy.w",{DSP_REG_A_M,AY_IND_N},{PPI,MOVY,HEX_9}, arch_sh_dsp_up}, +/* *n*m*1**10 movy.w ,@+ */ {"movy.w",{DSP_REG_A_M,AY_INC_N},{PPI,MOVY,HEX_A}, arch_sh_dsp_up}, +/* *n*m*1**11 movy.w ,@+r9 */ {"movy.w",{DSP_REG_A_M,AY_PMOD_N},{PPI,MOVY,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000001 movy.w @, */ {"movy.w",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm000010 movy.w @+, */{"movy.w",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm000011 movy.w @+r8, */{"movy.w",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm010001 movy.w ,@ */ {"movy.w",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_1,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm010010 movy.w ,@+ */{"movy.w",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_1,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm010011 movy.w ,@+r8 */{"movy.w",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_1,HEX_3}, arch_sh4al_dsp_up}, + +/* nnmm100001 movy.l @, */ {"movy.l",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm100010 movy.l @+, */{"movy.l",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm100011 movy.l @+r8, */{"movy.l",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm110001 movy.l ,@ */ {"movy.l",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_3,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm110010 movy.l ,@+ */{"movy.l",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_3,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm110011 movy.l ,@+r8 */{"movy.l",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_3,HEX_3}, arch_sh4al_dsp_up}, + +/* 01aaeeffxxyyggnn pmuls Se,Sf,Dg */ {"pmuls",{DSP_REG_E,DSP_REG_F,DSP_REG_G},{PPI,PMUL}, arch_sh_dsp_up}, +/* 10100000xxyynnnn psubc ,, */ +{"psubc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_0}, arch_sh_dsp_up}, +/* 10110000xxyynnnn paddc ,, */ +{"paddc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_0}, arch_sh_dsp_up}, +/* 10000100xxyynnnn pcmp , */ +{"pcmp", {DSP_REG_X,DSP_REG_Y},{PPI,PPI3,HEX_8,HEX_4}, arch_sh_dsp_up}, +/* 10100100xxyynnnn pwsb ,, */ +{"pwsb", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_4}, arch_sh_dsp_up}, +/* 10110100xxyynnnn pwad ,, */ +{"pwad", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_4}, arch_sh_dsp_up}, +/* 10001000xxyynnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_8,HEX_8}, arch_sh_dsp_up}, +/* 1000100!xx01nnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10101000xxyynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_A,HEX_8}, arch_sh_dsp_up}, +/* 1010100!01yynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9,HEX_4}, arch_sh4al_dsp_up}, +/* 10011000xxyynnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_9,HEX_8}, arch_sh_dsp_up}, +/* 1001100!xx01nnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10111000xxyynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_B,HEX_8}, arch_sh_dsp_up}, +/* 1011100!01yynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_4}, arch_sh4al_dsp_up}, + +{"dct",{0},{PPI,PDC,HEX_1}, arch_sh_dsp_up}, +{"dcf",{0},{PPI,PDC,HEX_2}, arch_sh_dsp_up}, + +/* 10000001xxyynnnn pshl ,, */ +{"pshl", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_1}, arch_sh_dsp_up}, +/* 00000iiiiiiinnnn pshl #, */ {"pshl",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_0}, arch_sh_dsp_up}, +/* 10010001xxyynnnn psha ,, */ +{"psha", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_1}, arch_sh_dsp_up}, +/* 00010iiiiiiinnnn psha #, */ {"psha",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_1}, arch_sh_dsp_up}, +/* 10100001xxyynnnn psub ,, */ +{"psub", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_1}, arch_sh_dsp_up}, +/* 10000101xxyynnnn psub ,, */ +{"psub", {DSP_REG_Y,DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_5}, arch_sh4al_dsp_up}, +/* 10110001xxyynnnn padd ,, */ +{"padd", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_1}, arch_sh_dsp_up}, +/* 10010101xxyynnnn pand ,, */ +{"pand", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_5}, arch_sh_dsp_up}, +/* 10100101xxyynnnn pxor ,, */ +{"pxor", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_5}, arch_sh_dsp_up}, +/* 10110101xxyynnnn por ,, */ +{"por", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_5}, arch_sh_dsp_up}, +/* 10001001xxyynnnn pdec , */ +{"pdec", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9}, arch_sh_dsp_up}, +/* 10101001xxyynnnn pdec , */ +{"pdec", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9}, arch_sh_dsp_up}, +/* 10011001xx00nnnn pinc , */ +{"pinc", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_XX00}, arch_sh_dsp_up}, +/* 1011100100yynnnn pinc , */ +{"pinc", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_00YY}, arch_sh_dsp_up}, +/* 10001101xxyynnnn pclr */ +{"pclr", {DSP_REG_N},{PPI,PPIC,HEX_8,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx00nnnn pdmsb , */ +{"pdmsb", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_XX00}, arch_sh_dsp_up}, +/* 1011110100yynnnn pdmsb , */ +{"pdmsb", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_00YY}, arch_sh_dsp_up}, +/* 11001001xxyynnnn pneg , */ +{"pneg", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_9}, arch_sh_dsp_up}, +/* 11101001xxyynnnn pneg , */ +{"pneg", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_E,HEX_9}, arch_sh_dsp_up}, +/* 11011001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_9}, arch_sh_dsp_up}, +/* 11111001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_F,HEX_9}, arch_sh_dsp_up}, +/* 11001101xxyynnnn psts MACH, */ +{"psts", {A_MACH,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_D}, arch_sh_dsp_up}, +/* 11011101xxyynnnn psts MACL, */ +{"psts", {A_MACL,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_D}, arch_sh_dsp_up}, +/* 11101101xxyynnnn plds ,MACH */ +{"plds", {DSP_REG_N,A_MACH},{PPI,PPIC,HEX_E,HEX_D}, arch_sh_dsp_up}, +/* 11111101xxyynnnn plds ,MACL */ +{"plds", {DSP_REG_N,A_MACL},{PPI,PPIC,HEX_F,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx01zzzz pswap , */ +{"pswap", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_1}, arch_sh4al_dsp_up}, +/* 1011110101yyzzzz pswap , */ +{"pswap", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_4}, arch_sh4al_dsp_up}, + +/* 1111nnnn01011101 fabs */{"fabs",{F_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh2e_up}, +/* 1111nnn001011101 fabs */{"fabs",{D_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0000 fadd ,*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh2e_up}, +/* 1111nnn0mmm00000 fadd ,*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0100 fcmp/eq ,*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh2e_up}, +/* 1111nnn0mmm00100 fcmp/eq ,*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0101 fcmp/gt ,*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh2e_up}, +/* 1111nnn0mmm00101 fcmp/gt ,*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010111101 fcnvds ,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N_D,HEX_B,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010101101 fcnvsd FPUL,*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_A,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0011 fdiv ,*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh2e_up}, +/* 1111nnn0mmm00011 fdiv ,*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnmm11101101 fipr ,*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}, arch_sh4_up}, + +/* 1111nnnn10001101 fldi0 */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn10011101 fldi1 */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00011101 flds ,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00101101 float FPUL,*/{"float",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh2e_up}, +/* 1111nnn000101101 float FPUL,*/{"float",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1110 fmac FR0,,*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}, arch_sh2e_up}, + +/* 1111nnnnmmmm1100 fmov ,*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh2e_up}, +/* 1111nnn1mmmm1100 fmov ,*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1000 fmov @,*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, +/* 1111nnn1mmmm1000 fmov @,*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1010 fmov ,@*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, +/* 1111nnnnmmm11010 fmov ,@*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1001 fmov @+,*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, +/* 1111nnn1mmmm1001 fmov @+,*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1011 fmov ,@-*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, +/* 1111nnnnmmm11011 fmov ,@-*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, +/* 1111nnn1mmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0111 fmov ,@(R0,)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 1111nnnnmmm10111 fmov ,@(R0,)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1000 fmov.d @,*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11010 fmov.d ,@*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1001 fmov.d @+,*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11011 fmov.d ,@-*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm0110 fmov.d @(R0,),*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm10111 fmov.d ,@(R0,)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.d ,@(,) */ +{"fmov.d",{DX_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY8}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.d @(,),F_REG_N */ +{"fmov.d",{A_DISP_REG_M,DX_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY8}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm1000 fmov.s @,*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, + +/* 1111nnnnmmmm1010 fmov.s ,@*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, + +/* 1111nnnnmmmm1001 fmov.s @+,*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, + +/* 1111nnnnmmmm1011 fmov.s ,@-*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, + +/* 1111nnnnmmmm0110 fmov.s @(R0,),*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, + +/* 1111nnnnmmmm0111 fmov.s ,@(R0,)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.s ,@(,) */ +{"fmov.s",{F_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY4}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.s @(,),F_REG_N */ +{"fmov.s",{A_DISP_REG_M,F_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY4}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm0010 fmul ,*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh2e_up}, +/* 1111nnn0mmm00010 fmul ,*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01001101 fneg */{"fneg",{F_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh2e_up}, +/* 1111nnn001001101 fneg */{"fneg",{D_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111011111111101 fpchg */{"fpchg",{0},{HEX_F,HEX_7,HEX_F,HEX_D}, arch_sh4a_up}, + +/* 1111101111111101 frchg */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111nnn011111101 fsca FPUL, */{"fsca",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111001111111101 fschg */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01101101 fsqrt */{"fsqrt",{F_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh3e_up | arch_sh2a_up}, +/* 1111nnn001101101 fsqrt */{"fsqrt",{D_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01111101 fsrra */{"fsrra",{F_REG_N},{HEX_F,REG_N,HEX_7,HEX_D}, arch_sh4_up}, + +/* 1111nnnn00001101 fsts FPUL,*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}, arch_sh2e_up}, + +/* 1111nnnnmmmm0001 fsub ,*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh2e_up}, +/* 1111nnn0mmm00001 fsub ,*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh2e_up}, +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nn0111111101 ftrv XMTRX_M4,*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_N_B01,HEX_F,HEX_D}, arch_sh4_up}, + + /* 10000110nnnn0iii bclr #, */ {"bclr",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0000dddddddddddd bclr.b #,@(,) */ +{"bclr.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn1iii bld #, */ {"bld",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0011dddddddddddd bld.b #,@(,) */ +{"bld.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_3,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000110nnnn1iii bset #, */ {"bset",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0001dddddddddddd bset.b #,@(,) */ +{"bset.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_1,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn0iii bst #, */ {"bst",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0010dddddddddddd bst.b #,@(,) */ +{"bst.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_2,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 0100nnnn10010001 clips.b */ {"clips.b",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010101 clips.w */ {"clips.w",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000001 clipu.b */ {"clipu.b",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000101 clipu.w */ {"clipu.w",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010100 divs R0, */ {"divs",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_9,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000100 divu R0, */ {"divu",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100mmmm01001011 jsr/n @ */ {"jsr/n",{A_IND_M},{HEX_4,REG_M,HEX_4,HEX_B}, arch_sh2a_nofpu_up}, + /* 10000011dddddddd jsr/n @@(,TBR) */ {"jsr/n",{A_DISP2_TBR},{HEX_8,HEX_3,IMM0_8BY4}, arch_sh2a_nofpu_up}, + /* 0100mmmm11100101 ldbank @,R0 */ {"ldbank",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110001 movml.l ,@-R15 */ {"movml.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110101 movml.l @R15+, */ {"movml.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110000 movml.l ,@-R15 */ {"movmu.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_0}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110100 movml.l @R15+, */ {"movmu.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_4}, arch_sh2a_nofpu_up}, + /* 0000nnnn00111001 movrt */ {"movrt",{A_REG_N},{HEX_0,REG_N,HEX_3,HEX_9}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000000 mulr R0, */ {"mulr",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_0}, arch_sh2a_nofpu_up}, + /* 0000000001101000 nott */ {"nott",{A_END},{HEX_0,HEX_0,HEX_6,HEX_8}, arch_sh2a_nofpu_up}, + /* 0000000001011011 resbank */ {"resbank",{A_END},{HEX_0,HEX_0,HEX_5,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000000001101011 rts/n */ {"rts/n",{A_END},{HEX_0,HEX_0,HEX_6,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000mmmm01111011 rtv/n */ {"rtv/n",{A_REG_M},{HEX_0,REG_M,HEX_7,HEX_B}, arch_sh2a_nofpu_up}, + /* 0100nnnn11100001 stbank R0,@*/ {"stbank",{A_R0,A_IND_N},{HEX_4,REG_N,HEX_E,HEX_1}, arch_sh2a_nofpu_up}, + +/* 0011nnnn0iii1001 0100dddddddddddd band.b #,@(,) */ +{"band.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_4,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1100dddddddddddd bandnot.b #,@(,) */ +{"bandnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_C,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1011dddddddddddd bldnot.b #,@(,) */ +{"bldnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_B,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0101dddddddddddd bor.b #,@(,) */ +{"bor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_5,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1101dddddddddddd bornot.b #,@(,) */ +{"bornot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_D,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0110dddddddddddd bxor.b #,@(,) */ +{"bxor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_6,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0000 iiiiiiiiiiiiiiii movi20 #, */ +{"movi20",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_0,IMM0_20}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0001 iiiiiiiiiiiiiiii movi20s #, */ +{"movi20s",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_1,IMM0_20BY8}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1000dddddddddddd movu.b @(,), */ +{"movu.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_8,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(,), */ +{"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, + +{ 0, {0}, {0}, 0 } +}; + +#endif + +#ifdef ARCH_all +#define INCLUDE_SHMEDIA +#endif + +static void print_movxy + (const sh_opcode_info *, int, int, fprintf_ftype, void *); +static void print_insn_ddt (int, struct disassemble_info *); +static void print_dsp_reg (int, fprintf_ftype, void *); +static void print_insn_ppi (int, struct disassemble_info *); + +static void +print_movxy (const sh_opcode_info *op, int rn, int rm, + fprintf_ftype fprintf_fn, void *stream) +{ + int n; + + fprintf_fn (stream, "%s\t", op->name); + for (n = 0; n < 2; n++) + { + switch (op->arg[n]) + { + case A_IND_N: + case AX_IND_N: + case AXY_IND_N: + case AY_IND_N: + case AYX_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_INC_N: + case AX_INC_N: + case AXY_INC_N: + case AY_INC_N: + case AYX_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case AX_PMOD_N: + case AXY_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case AY_PMOD_N: + case AYX_PMOD_N: + fprintf_fn (stream, "@r%d+r9", rn); + break; + case DSP_REG_A_M: + fprintf_fn (stream, "a%c", '0' + rm); + break; + case DSP_REG_X: + fprintf_fn (stream, "x%c", '0' + rm); + break; + case DSP_REG_Y: + fprintf_fn (stream, "y%c", '0' + rm); + break; + case DSP_REG_AX: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'x' : 'a', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_XY: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'y' : 'x', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_AY: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'y' : 'a', + (rm & 1) ? '1' : '0'); + break; + case DSP_REG_YX: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'x' : 'y', + (rm & 1) ? '1' : '0'); + break; + default: + abort (); + } + if (n == 0) + fprintf_fn (stream, ","); + } +} + +/* Print a double data transfer insn. INSN is just the lower three + nibbles of the insn, i.e. field a and the bit that indicates if + a parallel processing insn follows. + Return nonzero if a field b of a parallel processing insns follows. */ + +static void +print_insn_ddt (int insn, struct disassemble_info *info) +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + + /* If this is just a nop, make sure to emit something. */ + if (insn == 0x000) + fprintf_fn (stream, "nopx\tnopy"); + + /* If a parallel processing insn was printed before, + and we got a non-nop, emit a tab. */ + if ((insn & 0x800) && (insn & 0x3ff)) + fprintf_fn (stream, "\t"); + + /* Check if either the x or y part is invalid. */ + if (((insn & 0xc) == 0 && (insn & 0x2a0)) + || ((insn & 3) == 0 && (insn & 0x150))) + if (info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *op; + int is_movy; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;) + first_movy++; + } + + is_movy = ((insn & 3) != 0); + + if (is_movy) + op = first_movy; + else + op = first_movx; + + while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3) + || op->nibbles[3] != (unsigned) (insn & 0xf)) + op++; + + print_movxy (op, + (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0) + + 2 * is_movy + + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)), + (insn >> 6) & 3, + fprintf_fn, stream); + } + else + fprintf_fn (stream, ".word 0x%x", insn); + else + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *opx, *opy; + unsigned int insn_x, insn_y; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;) + first_movy++; + } + insn_x = (insn >> 2) & 0xb; + if (insn_x) + { + for (opx = first_movx; opx->nibbles[2] != insn_x;) + opx++; + print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1, + fprintf_fn, stream); + } + insn_y = (insn & 3) | ((insn >> 1) & 8); + if (insn_y) + { + if (insn_x) + fprintf_fn (stream, "\t"); + for (opy = first_movy; opy->nibbles[2] != insn_y;) + opy++; + print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1, + fprintf_fn, stream); + } + } +} + +static void +print_dsp_reg (int rm, fprintf_ftype fprintf_fn, void *stream) +{ + switch (rm) + { + case A_A1_NUM: + fprintf_fn (stream, "a1"); + break; + case A_A0_NUM: + fprintf_fn (stream, "a0"); + break; + case A_X0_NUM: + fprintf_fn (stream, "x0"); + break; + case A_X1_NUM: + fprintf_fn (stream, "x1"); + break; + case A_Y0_NUM: + fprintf_fn (stream, "y0"); + break; + case A_Y1_NUM: + fprintf_fn (stream, "y1"); + break; + case A_M0_NUM: + fprintf_fn (stream, "m0"); + break; + case A_A1G_NUM: + fprintf_fn (stream, "a1g"); + break; + case A_M1_NUM: + fprintf_fn (stream, "m1"); + break; + case A_A0G_NUM: + fprintf_fn (stream, "a0g"); + break; + default: + fprintf_fn (stream, "0x%x", rm); + break; + } +} + +static void +print_insn_ppi (int field_b, struct disassemble_info *info) +{ + static const char *sx_tab[] = { "x0", "x1", "a0", "a1" }; + static const char *sy_tab[] = { "y0", "y1", "m0", "m1" }; + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned int nib1, nib2, nib3; + unsigned int altnib1, nib4; + const char *dc = NULL; + const sh_opcode_info *op; + + if ((field_b & 0xe800) == 0) + { + fprintf_fn (stream, "psh%c\t#%d,", + field_b & 0x1000 ? 'a' : 'l', + (field_b >> 4) & 127); + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + return; + } + if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000) + { + static const char *du_tab[] = { "x0", "y0", "a0", "a1" }; + static const char *se_tab[] = { "x0", "x1", "y0", "a1" }; + static const char *sf_tab[] = { "y0", "y1", "x0", "a1" }; + static const char *sg_tab[] = { "m0", "m1", "a0", "a1" }; + + if (field_b & 0x2000) + { + fprintf_fn (stream, "p%s %s,%s,%s\t", + (field_b & 0x1000) ? "add" : "sub", + sx_tab[(field_b >> 6) & 3], + sy_tab[(field_b >> 4) & 3], + du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf0) == 0x10 + && info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf3) != 0) + { + fprintf_fn (stream, ".word 0x%x\t", field_b); + } + fprintf_fn (stream, "pmuls%c%s,%s,%s", + field_b & 0x2000 ? ' ' : '\t', + se_tab[(field_b >> 10) & 3], + sf_tab[(field_b >> 8) & 3], + sg_tab[(field_b >> 2) & 3]); + return; + } + + nib1 = PPIC; + nib2 = field_b >> 12 & 0xf; + nib3 = field_b >> 8 & 0xf; + nib4 = field_b >> 4 & 0xf; + switch (nib3 & 0x3) + { + case 0: + dc = ""; + nib1 = PPI3; + break; + case 1: + dc = ""; + break; + case 2: + dc = "dct "; + nib3 -= 1; + break; + case 3: + dc = "dcf "; + nib3 -= 2; + break; + } + if (nib1 == PPI3) + altnib1 = PPI3NC; + else + altnib1 = nib1; + for (op = sh_table; op->name; op++) + { + if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1) + && op->nibbles[2] == nib2 + && op->nibbles[3] == nib3) + { + int n; + + switch (op->nibbles[4]) + { + case HEX_0: + break; + case HEX_XX00: + if ((nib4 & 3) != 0) + continue; + break; + case HEX_1: + if ((nib4 & 3) != 1) + continue; + break; + case HEX_00YY: + if ((nib4 & 0xc) != 0) + continue; + break; + case HEX_4: + if ((nib4 & 0xc) != 4) + continue; + break; + default: + abort (); + } + fprintf_fn (stream, "%s%s\t", dc, op->name); + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case DSP_REG_N: + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + break; + case DSP_REG_X: + fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]); + break; + case DSP_REG_Y: + fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + default: + abort (); + } + } + return; + } + } + /* Not found. */ + fprintf_fn (stream, ".word 0x%x", field_b); +} + +/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff + (ie. the upper nibble is missing). */ +int +print_insn_sh (bfd_vma memaddr, struct disassemble_info *info) +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned char insn[4]; + unsigned char nibs[8]; + int status; + bfd_vma relmask = ~(bfd_vma) 0; + const sh_opcode_info *op; + unsigned int target_arch; + int allow_op32; + + switch (info->mach) + { + case bfd_mach_sh: + target_arch = arch_sh1; + break; + case bfd_mach_sh4: + target_arch = arch_sh4; + break; + case bfd_mach_sh5: +#ifdef INCLUDE_SHMEDIA + status = print_insn_sh64 (memaddr, info); + if (status != -2) + return status; +#endif + /* When we get here for sh64, it's because we want to disassemble + SHcompact, i.e. arch_sh4. */ + target_arch = arch_sh4; + break; + default: + fprintf (stderr, "sh architecture not supported\n"); + return -1; + } + + status = info->read_memory_func (memaddr, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[0] = (insn[1] >> 4) & 0xf; + nibs[1] = insn[1] & 0xf; + + nibs[2] = (insn[0] >> 4) & 0xf; + nibs[3] = insn[0] & 0xf; + } + else + { + nibs[0] = (insn[0] >> 4) & 0xf; + nibs[1] = insn[0] & 0xf; + + nibs[2] = (insn[1] >> 4) & 0xf; + nibs[3] = insn[1] & 0xf; + } + status = info->read_memory_func (memaddr + 2, insn + 2, 2, info); + if (status != 0) + allow_op32 = 0; + else + { + allow_op32 = 1; + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[4] = (insn[3] >> 4) & 0xf; + nibs[5] = insn[3] & 0xf; + + nibs[6] = (insn[2] >> 4) & 0xf; + nibs[7] = insn[2] & 0xf; + } + else + { + nibs[4] = (insn[2] >> 4) & 0xf; + nibs[5] = insn[2] & 0xf; + + nibs[6] = (insn[3] >> 4) & 0xf; + nibs[7] = insn[3] & 0xf; + } + } + + if (nibs[0] == 0xf && (nibs[1] & 4) == 0 + && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up)) + { + if (nibs[1] & 8) + { + int field_b; + + status = info->read_memory_func (memaddr + 2, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr + 2, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + field_b = insn[1] << 8 | insn[0]; + else + field_b = insn[0] << 8 | insn[1]; + + print_insn_ppi (field_b, info); + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 4; + } + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 2; + } + for (op = sh_table; op->name; op++) + { + int n; + int imm = 0; + int rn = 0; + int rm = 0; + int rb = 0; + int disp_pc; + bfd_vma disp_pc_addr = 0; + int disp = 0; + int has_disp = 0; + int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4; + + if (!allow_op32 + && SH_MERGE_ARCH_SET (op->arch, arch_op32)) + goto fail; + + if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch)) + goto fail; + for (n = 0; n < max_n; n++) + { + int i = op->nibbles[n]; + + if (i < 16) + { + if (nibs[n] == i) + continue; + goto fail; + } + switch (i) + { + case BRANCH_8: + imm = (nibs[2] << 4) | (nibs[3]); + if (imm & 0x80) + imm |= ~0xff; + imm = ((char) imm) * 2 + 4; + goto ok; + case BRANCH_12: + imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]); + if (imm & 0x800) + imm |= ~0xfff; + imm = imm * 2 + 4; + goto ok; + case IMM0_3c: + if (nibs[3] & 0x8) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3s: + if (!(nibs[3] & 0x8)) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3Uc: + if (nibs[2] & 0x8) + goto fail; + imm = nibs[2] & 0x7; + break; + case IMM0_3Us: + if (!(nibs[2] & 0x8)) + goto fail; + imm = nibs[2] & 0x7; + break; + case DISP0_12: + case DISP1_12: + disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7]; + has_disp = 1; + goto ok; + case DISP0_12BY2: + case DISP1_12BY2: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1; + relmask = ~(bfd_vma) 1; + has_disp = 1; + goto ok; + case DISP0_12BY4: + case DISP1_12BY4: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2; + relmask = ~(bfd_vma) 3; + has_disp = 1; + goto ok; + case DISP0_12BY8: + case DISP1_12BY8: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3; + relmask = ~(bfd_vma) 7; + has_disp = 1; + goto ok; + case IMM0_20_4: + break; + case IMM0_20: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + if (imm & 0x80000) + imm -= 0x100000; + goto ok; + case IMM0_20BY8: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + imm <<= 8; + if (imm & 0x8000000) + imm -= 0x10000000; + goto ok; + case IMM0_4: + case IMM1_4: + imm = nibs[3]; + goto ok; + case IMM0_4BY2: + case IMM1_4BY2: + imm = nibs[3] << 1; + goto ok; + case IMM0_4BY4: + case IMM1_4BY4: + imm = nibs[3] << 2; + goto ok; + case IMM0_8: + case IMM1_8: + imm = (nibs[2] << 4) | nibs[3]; + disp = imm; + has_disp = 1; + if (imm & 0x80) + imm -= 0x100; + goto ok; + case PCRELIMM_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + relmask = ~(bfd_vma) 1; + goto ok; + case PCRELIMM_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + relmask = ~(bfd_vma) 3; + goto ok; + case IMM0_8BY2: + case IMM1_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + goto ok; + case IMM0_8BY4: + case IMM1_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + goto ok; + case REG_N_D: + if ((nibs[n] & 1) != 0) + goto fail; + /* fall through */ + case REG_N: + rn = nibs[n]; + break; + case REG_M: + rm = nibs[n]; + break; + case REG_N_B01: + if ((nibs[n] & 0x3) != 1 /* binary 01 */) + goto fail; + rn = (nibs[n] & 0xc) >> 2; + break; + case REG_NM: + rn = (nibs[n] & 0xc) >> 2; + rm = (nibs[n] & 0x3); + break; + case REG_B: + rb = nibs[n] & 0x07; + break; + case SDT_REG_N: + /* sh-dsp: single data transfer. */ + rn = nibs[n]; + if ((rn & 0xc) != 4) + goto fail; + rn = rn & 0x3; + rn |= (!(rn & 2)) << 2; + break; + case PPI: + case REPEAT: + goto fail; + default: + abort (); + } + } + + ok: + /* sh2a has D_REG but not X_REG. We don't know the pattern + doesn't match unless we check the output args to see if they + make sense. */ + if (target_arch == arch_sh2a + && ((op->arg[0] == DX_REG_M && (rm & 1) != 0) + || (op->arg[1] == DX_REG_N && (rn & 1) != 0))) + goto fail; + + fprintf_fn (stream, "%s\t", op->name); + disp_pc = 0; + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case A_IMM: + fprintf_fn (stream, "#%d", imm); + break; + case A_R0: + fprintf_fn (stream, "r0"); + break; + case A_REG_N: + fprintf_fn (stream, "r%d", rn); + break; + case A_INC_N: + case AS_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case A_DEC_N: + case AS_DEC_N: + fprintf_fn (stream, "@-r%d", rn); + break; + case A_IND_N: + case AS_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_DISP_REG_N: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn); + break; + case AS_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case A_REG_M: + fprintf_fn (stream, "r%d", rm); + break; + case A_INC_M: + fprintf_fn (stream, "@r%d+", rm); + break; + case A_DEC_M: + fprintf_fn (stream, "@-r%d", rm); + break; + case A_IND_M: + fprintf_fn (stream, "@r%d", rm); + break; + case A_DISP_REG_M: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm); + break; + case A_REG_B: + fprintf_fn (stream, "r%d_bank", rb); + break; + case A_DISP_PC: + disp_pc = 1; + disp_pc_addr = imm + 4 + (memaddr & relmask); + (*info->print_address_func) (disp_pc_addr, info); + break; + case A_IND_R0_REG_N: + fprintf_fn (stream, "@(r0,r%d)", rn); + break; + case A_IND_R0_REG_M: + fprintf_fn (stream, "@(r0,r%d)", rm); + break; + case A_DISP_GBR: + fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm); + break; + case A_TBR: + fprintf_fn (stream, "tbr"); + break; + case A_DISP2_TBR: + fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm); + break; + case A_INC_R15: + fprintf_fn (stream, "@r15+"); + break; + case A_DEC_R15: + fprintf_fn (stream, "@-r15"); + break; + case A_R0_GBR: + fprintf_fn (stream, "@(r0,gbr)"); + break; + case A_BDISP12: + case A_BDISP8: + { + bfd_vma addr; + addr = imm + memaddr; + (*info->print_address_func) (addr, info); + } + break; + case A_SR: + fprintf_fn (stream, "sr"); + break; + case A_GBR: + fprintf_fn (stream, "gbr"); + break; + case A_VBR: + fprintf_fn (stream, "vbr"); + break; + case A_DSR: + fprintf_fn (stream, "dsr"); + break; + case A_MOD: + fprintf_fn (stream, "mod"); + break; + case A_RE: + fprintf_fn (stream, "re"); + break; + case A_RS: + fprintf_fn (stream, "rs"); + break; + case A_A0: + fprintf_fn (stream, "a0"); + break; + case A_X0: + fprintf_fn (stream, "x0"); + break; + case A_X1: + fprintf_fn (stream, "x1"); + break; + case A_Y0: + fprintf_fn (stream, "y0"); + break; + case A_Y1: + fprintf_fn (stream, "y1"); + break; + case DSP_REG_M: + print_dsp_reg (rm, fprintf_fn, stream); + break; + case A_SSR: + fprintf_fn (stream, "ssr"); + break; + case A_SPC: + fprintf_fn (stream, "spc"); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + case A_PR: + fprintf_fn (stream, "pr"); + break; + case A_SGR: + fprintf_fn (stream, "sgr"); + break; + case A_DBR: + fprintf_fn (stream, "dbr"); + break; + case F_REG_N: + fprintf_fn (stream, "fr%d", rn); + break; + case F_REG_M: + fprintf_fn (stream, "fr%d", rm); + break; + case DX_REG_N: + if (rn & 1) + { + fprintf_fn (stream, "xd%d", rn & ~1); + break; + } + case D_REG_N: + fprintf_fn (stream, "dr%d", rn); + break; + case DX_REG_M: + if (rm & 1) + { + fprintf_fn (stream, "xd%d", rm & ~1); + break; + } + case D_REG_M: + fprintf_fn (stream, "dr%d", rm); + break; + case FPSCR_M: + case FPSCR_N: + fprintf_fn (stream, "fpscr"); + break; + case FPUL_M: + case FPUL_N: + fprintf_fn (stream, "fpul"); + break; + case F_FR0: + fprintf_fn (stream, "fr0"); + break; + case V_REG_N: + fprintf_fn (stream, "fv%d", rn * 4); + break; + case V_REG_M: + fprintf_fn (stream, "fv%d", rm * 4); + break; + case XMTRX_M4: + fprintf_fn (stream, "xmtrx"); + break; + default: + abort (); + } + } + +#if 0 + /* This code prints instructions in delay slots on the same line + as the instruction which needs the delay slots. This can be + confusing, since other disassembler don't work this way, and + it means that the instructions are not all in a line. So I + disabled it. Ian. */ + if (!(info->flags & 1) + && (op->name[0] == 'j' + || (op->name[0] == 'b' + && (op->name[1] == 'r' + || op->name[1] == 's')) + || (op->name[0] == 'r' && op->name[1] == 't') + || (op->name[0] == 'b' && op->name[2] == '.'))) + { + info->flags |= 1; + fprintf_fn (stream, "\t(slot "); + print_insn_sh (memaddr + 2, info); + info->flags &= ~1; + fprintf_fn (stream, ")"); + return 4; + } +#endif + + if (disp_pc && strcmp (op->name, "mova") != 0) + { + int size; + bfd_byte bytes[4]; + + if (relmask == ~(bfd_vma) 1) + size = 2; + else + size = 4; + status = info->read_memory_func (disp_pc_addr, bytes, size, info); + if (status == 0) + { + unsigned int val; + + if (size == 2) + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl16 (bytes); + else + val = bfd_getb16 (bytes); + } + else + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl32 (bytes); + else + val = bfd_getb32 (bytes); + } + if ((*info->symbol_at_address_func) (val, info)) + { + fprintf_fn (stream, "\t! "); + (*info->print_address_func) (val, info); + } + else + fprintf_fn (stream, "\t! 0x%x", val); + } + } + + return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2; + fail: + ; + + } + fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]); + return 2; +} diff --git a/qemu/qemu-git/.svn/text-base/softmmu_defs.h.svn-base b/qemu/qemu-git/.svn/text-base/softmmu_defs.h.svn-base new file mode 100644 index 0000000..e38bb75 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/softmmu_defs.h.svn-base @@ -0,0 +1,22 @@ +#ifndef SOFTMMU_DEFS_H +#define SOFTMMU_DEFS_H + +uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); + +uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); + +#endif diff --git a/qemu/qemu-git/.svn/text-base/softmmu_exec.h.svn-base b/qemu/qemu-git/.svn/text-base/softmmu_exec.h.svn-base new file mode 100644 index 0000000..a43e621 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/softmmu_exec.h.svn-base @@ -0,0 +1,134 @@ +/* Common softmmu definitions and inline routines. */ + +/* XXX: find something cleaner. + * Furthermore, this is false for 64 bits targets + */ +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel +#define ldul_hypv ldl_hypv +#define ldul_executive ldl_executive +#define ldul_supervisor ldl_supervisor + +#include "softmmu_defs.h" + +#define ACCESS_TYPE 0 +#define MEMSUFFIX MMU_MODE0_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX MMU_MODE1_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#if (NB_MMU_MODES >= 3) + +#define ACCESS_TYPE 2 +#define MEMSUFFIX MMU_MODE2_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 3) */ + +#if (NB_MMU_MODES >= 4) + +#define ACCESS_TYPE 3 +#define MEMSUFFIX MMU_MODE3_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 4) */ + +#if (NB_MMU_MODES >= 5) + +#define ACCESS_TYPE 4 +#define MEMSUFFIX MMU_MODE4_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 5) */ + +#if (NB_MMU_MODES > 5) +#error "NB_MMU_MODES > 5 is not supported for now" +#endif /* (NB_MMU_MODES > 5) */ + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE (NB_MMU_MODES) +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) diff --git a/qemu/qemu-git/.svn/text-base/softmmu_header.h.svn-base b/qemu/qemu-git/.svn/text-base/softmmu_header.h.svn-base new file mode 100644 index 0000000..6a36e01 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/softmmu_header.h.svn-base @@ -0,0 +1,198 @@ +/* + * Software MMU support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#if DATA_SIZE == 8 +#define SUFFIX q +#define USUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define USUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define USUFFIX uw +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define USUFFIX ub +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#else +#error unsupported data size +#endif + +#if ACCESS_TYPE < (NB_MMU_MODES) + +#define CPU_MMU_INDEX ACCESS_TYPE +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == (NB_MMU_MODES) + +#define CPU_MMU_INDEX (cpu_mmu_index(env)) +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == (NB_MMU_MODES + 1) + +#define CPU_MMU_INDEX (cpu_mmu_index(env)) +#define MMUSUFFIX _cmmu + +#else +#error invalid ACCESS_TYPE +#endif + +#if DATA_SIZE == 8 +#define RES_TYPE uint64_t +#else +#define RES_TYPE int +#endif + +#if ACCESS_TYPE == (NB_MMU_MODES + 1) +#define ADDR_READ addr_code +#else +#define ADDR_READ addr_read +#endif + +/* generic load/store macros */ + +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) +{ + int page_index; + RES_TYPE res; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} + +#if DATA_SIZE <= 2 +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) +{ + int res, page_index; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} +#endif + +#if ACCESS_TYPE != (NB_MMU_MODES + 1) + +/* generic store macro */ + +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) +{ + int page_index; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); + } +} + +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ + +#if ACCESS_TYPE != (NB_MMU_MODES + 1) + +#if DATA_SIZE == 8 +static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) +{ + union { + float64 d; + uint64_t i; + } u; + u.i = glue(ldq, MEMSUFFIX)(ptr); + return u.d; +} + +static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) +{ + union { + float64 d; + uint64_t i; + } u; + u.d = v; + glue(stq, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 8 */ + +#if DATA_SIZE == 4 +static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = glue(ldl, MEMSUFFIX)(ptr); + return u.f; +} + +static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + glue(stl, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 4 */ + +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ + +#undef RES_TYPE +#undef DATA_TYPE +#undef DATA_STYPE +#undef SUFFIX +#undef USUFFIX +#undef DATA_SIZE +#undef CPU_MMU_INDEX +#undef MMUSUFFIX +#undef ADDR_READ diff --git a/qemu/qemu-git/.svn/text-base/softmmu_template.h.svn-base b/qemu/qemu-git/.svn/text-base/softmmu_template.h.svn-base new file mode 100644 index 0000000..0e13153 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/softmmu_template.h.svn-base @@ -0,0 +1,327 @@ +/* + * Software MMU support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#define DATA_SIZE (1 << SHIFT) + +#if DATA_SIZE == 8 +#define SUFFIX q +#define USUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define USUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define USUFFIX uw +#define DATA_TYPE uint16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define USUFFIX ub +#define DATA_TYPE uint8_t +#else +#error unsupported data size +#endif + +#ifdef SOFTMMU_CODE_ACCESS +#define READ_ACCESS_TYPE 2 +#define ADDR_READ addr_code +#else +#define READ_ACCESS_TYPE 0 +#define ADDR_READ addr_read +#endif + +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx, + void *retaddr); +static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, + target_ulong addr, + void *retaddr) +{ + DATA_TYPE res; + int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + env->mem_io_pc = (unsigned long)retaddr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } + + env->mem_io_vaddr = addr; +#if SHIFT <= 2 + res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); +#else +#ifdef TARGET_WORDS_BIGENDIAN + res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32; + res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4); +#else + res = io_mem_read[index][2](io_mem_opaque[index], physaddr); + res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32; +#endif +#endif /* SHIFT > 2 */ + return res; +} + +/* handle all cases except unaligned access which span two pages */ +DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx) +{ + DATA_TYPE res; + int index; + target_ulong tlb_addr; + target_phys_addr_t addend; + void *retaddr; + + /* test if there is match for unaligned or IO access */ + /* XXX: could done more in memory macro in a non portable way */ + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + /* slow unaligned access (it spans two pages or IO) */ + do_unaligned_access: + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, + mmu_idx, retaddr); + } else { + /* unaligned/aligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + } +#endif + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + goto redo; + } + return res; +} + +/* handle all unaligned cases */ +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx, + void *retaddr) +{ + DATA_TYPE res, res1, res2; + int index, shift; + target_phys_addr_t addend; + target_ulong tlb_addr, addr1, addr2; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* slow unaligned access (it spans two pages) */ + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; + res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, + mmu_idx, retaddr); + res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, + mmu_idx, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; +#ifdef TARGET_WORDS_BIGENDIAN + res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); +#else + res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); +#endif + res = (DATA_TYPE)res; + } else { + /* unaligned/aligned access in the same page */ + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + goto redo; + } + return res; +} + +#ifndef SOFTMMU_CODE_ACCESS + +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx, + void *retaddr); + +static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, + DATA_TYPE val, + target_ulong addr, + void *retaddr) +{ + int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } + + env->mem_io_vaddr = addr; + env->mem_io_pc = (unsigned long)retaddr; +#if SHIFT <= 2 + io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); +#else +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val); +#else + io_mem_write[index][2](io_mem_opaque[index], physaddr, val); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); +#endif +#endif /* SHIFT > 2 */ +} + +void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx) +{ + target_phys_addr_t addend; + target_ulong tlb_addr; + void *retaddr; + int index; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, 1, mmu_idx, retaddr); +#endif + glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, + mmu_idx, retaddr); + } else { + /* aligned/unaligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, 1, mmu_idx, retaddr); + } +#endif + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, 1, mmu_idx, retaddr); +#endif + tlb_fill(addr, 1, mmu_idx, retaddr); + goto redo; + } +} + +/* handles all unaligned cases */ +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx, + void *retaddr) +{ + target_phys_addr_t addend; + target_ulong tlb_addr; + int index, i; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* XXX: not efficient, but simple */ + /* Note: relies on the fact that tlb_fill() does not remove the + * previous page from the TLB cache. */ + for(i = DATA_SIZE - 1; i >= 0; i--) { +#ifdef TARGET_WORDS_BIGENDIAN + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + mmu_idx, retaddr); +#else + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), + mmu_idx, retaddr); +#endif + } + } else { + /* aligned/unaligned access in the same page */ + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, 1, mmu_idx, retaddr); + goto redo; + } +} + +#endif /* !defined(SOFTMMU_CODE_ACCESS) */ + +#undef READ_ACCESS_TYPE +#undef SHIFT +#undef DATA_TYPE +#undef SUFFIX +#undef USUFFIX +#undef DATA_SIZE +#undef ADDR_READ diff --git a/qemu/qemu-git/.svn/text-base/sparc-dis.c.svn-base b/qemu/qemu-git/.svn/text-base/sparc-dis.c.svn-base new file mode 100644 index 0000000..83a12ae --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/sparc-dis.c.svn-base @@ -0,0 +1,3253 @@ +/* + * These files from binutils are concatenated: + * include/opcode/sparc.h, opcodes/sparc-opc.c, opcodes/sparc-dis.c + */ + +/* include/opcode/sparc.h */ + +/* Definitions for opcode table for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2002, + 2003, 2005 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and + the GNU Binutils. + + GAS/GDB is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS/GDB 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS or GDB; see the file COPYING. If not, + see . */ + +#include +#include "dis-asm.h" + +/* The SPARC opcode table (and other related data) is defined in + the opcodes library in sparc-opc.c. If you change anything here, make + sure you fix up that file, and vice versa. */ + + /* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* List of instruction sets variations. + These values are such that each element is either a superset of a + preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P + returns non-zero. + The values are indices into `sparc_opcode_archs' defined in sparc-opc.c. + Don't change this without updating sparc-opc.c. */ + +enum sparc_opcode_arch_val +{ + SPARC_OPCODE_ARCH_V6 = 0, + SPARC_OPCODE_ARCH_V7, + SPARC_OPCODE_ARCH_V8, + SPARC_OPCODE_ARCH_SPARCLET, + SPARC_OPCODE_ARCH_SPARCLITE, + /* V9 variants must appear last. */ + SPARC_OPCODE_ARCH_V9, + SPARC_OPCODE_ARCH_V9A, /* V9 with ultrasparc additions. */ + SPARC_OPCODE_ARCH_V9B, /* V9 with ultrasparc and cheetah additions. */ + SPARC_OPCODE_ARCH_BAD /* Error return from sparc_opcode_lookup_arch. */ +}; + +/* The highest architecture in the table. */ +#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1) + +/* Given an enum sparc_opcode_arch_val, return the bitmask to use in + insn encoding/decoding. */ +#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch)) + +/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9. */ +#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9) + +/* Table of cpu variants. */ + +typedef struct sparc_opcode_arch +{ + const char *name; + /* Mask of sparc_opcode_arch_val's supported. + EG: For v7 this would be + (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)). + These are short's because sparc_opcode.architecture is. */ + short supported; +} sparc_opcode_arch; + +static const struct sparc_opcode_arch sparc_opcode_archs[]; + +/* Return the bitmask of supported architectures for ARCH. */ +#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) + +/* Non-zero if ARCH1 conflicts with ARCH2. + IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ +#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ + (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH1)) \ + && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH2))) + +/* Structure of an opcode table entry. */ + +typedef struct sparc_opcode +{ + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* This was called "delayed" in versions before the flags. */ + char flags; + short architecture; /* Bitmask of sparc_opcode_arch_val's. */ +} sparc_opcode; + +#define F_DELAYED 1 /* Delayed branch. */ +#define F_ALIAS 2 /* Alias for a "real" instruction. */ +#define F_UNBR 4 /* Unconditional branch. */ +#define F_CONDBR 8 /* Conditional branch. */ +#define F_JSR 16 /* Subroutine call. */ +#define F_FLOAT 32 /* Floating point instruction (not a branch). */ +#define F_FBR 64 /* Floating point branch. */ +/* FIXME: Add F_ANACHRONISTIC flag for v9. */ + +/* All sparc opcodes are 32 bits, except for the `set' instruction (really a + macro), which is 64 bits. It is handled as a special case. + + The match component is a mask saying which bits must match a particular + opcode in order for an instruction to be an instance of that opcode. + + The args component is a string containing one character for each operand of the + instruction. + + Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + X 5 bit unsigned immediate + Y 6 bit unsigned immediate + 3 SIAM mode (3 bits). (v9b) + K MEMBAR mask (7 bits). (v9) + j 10 bit Immediate. (v9) + I 11 bit Immediate. (v9) + i 13 bit Immediate. + n 22 bit immediate. + k 2+14 bit PC relative immediate. (v9) + G 19 bit PC relative immediate. (v9) + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + N Branch predict clear ",pn" (v9) + T Branch predict set ",pt" (v9) + z %icc. (v9) + Z %xcc. (v9) + q Floating point queue. + r Single register that is both rs1 and rd. + O Single register that is both rs2 and rd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + u sparclet coprocessor registers in rd position + U sparclet coprocessor registers in rs1 position + E %ccr. (v9) + s %fprs. (v9) + P %pc. (v9) + W %tick. (v9) + o %asi. (v9) + 6 %fcc0. (v9) + 7 %fcc1. (v9) + 8 %fcc2. (v9) + 9 %fcc3. (v9) + ! Privileged Register in rd (v9) + ? Privileged Register in rs1 (v9) + * Prefetch function constant. (v9) + x OPF field (v9 impdep). + 0 32/64 bit immediate for set or setx (v9) insns + _ Ancillary state register in rd (v9a) + / Ancillary state register in rs1 (v9a) + + The following chars are unused: (note: ,[] are used as punctuation) + [45]. */ + +#define OP2(x) (((x) & 0x7) << 22) /* Op2 field of format2 insns. */ +#define OP3(x) (((x) & 0x3f) << 19) /* Op3 field of format3 insns. */ +#define OP(x) ((unsigned) ((x) & 0x3) << 30) /* Op field of all insns. */ +#define OPF(x) (((x) & 0x1ff) << 5) /* Opf field of float insns. */ +#define OPF_LOW5(x) OPF ((x) & 0x1f) /* V9. */ +#define F3F(x, y, z) (OP (x) | OP3 (y) | OPF (z)) /* Format3 float insns. */ +#define F3I(x) (((x) & 0x1) << 13) /* Immediate field of format 3 insns. */ +#define F2(x, y) (OP (x) | OP2(y)) /* Format 2 insns. */ +#define F3(x, y, z) (OP (x) | OP3(y) | F3I(z)) /* Format3 insns. */ +#define F1(x) (OP (x)) +#define DISP30(x) ((x) & 0x3fffffff) +#define ASI(x) (((x) & 0xff) << 5) /* Asi field of format3 insns. */ +#define RS2(x) ((x) & 0x1f) /* Rs2 field. */ +#define SIMM13(x) ((x) & 0x1fff) /* Simm13 field. */ +#define RD(x) (((x) & 0x1f) << 25) /* Destination register field. */ +#define RS1(x) (((x) & 0x1f) << 14) /* Rs1 field. */ +#define ASI_RS2(x) (SIMM13 (x)) +#define MEMBAR(x) ((x) & 0x7f) +#define SLCPOP(x) (((x) & 0x7f) << 6) /* Sparclet cpop. */ + +#define ANNUL (1 << 29) +#define BPRED (1 << 19) /* V9. */ +#define IMMED F3I (1) +#define RD_G0 RD (~0) +#define RS1_G0 RS1 (~0) +#define RS2_G0 RS2 (~0) + +static const struct sparc_opcode sparc_opcodes[]; + +static const char *sparc_decode_asi_v8 (int); +static const char *sparc_decode_asi_v9 (int); +static const char *sparc_decode_membar (int); +static const char *sparc_decode_prefetch (int); +static const char *sparc_decode_sparclet_cpreg (int); + +/* Local Variables: + fill-column: 131 + comment-column: 0 + End: */ + +/* opcodes/sparc-opc.c */ + +/* Table of opcodes for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of the BFD library. + + BFD is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + BFD 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with this software; see the file COPYING. If not, + see . */ + +/* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* Some defines to make life easy. */ +#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) +#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) +#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) +#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) +#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) +#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) +#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) +#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B) + +/* Bit masks of architectures supporting the insn. */ + +#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* v6 insns not supported on the sparclet. */ +#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* Although not all insns are implemented in hardware, sparclite is defined + to be a superset of v8. Unimplemented insns trap and are then theoretically + implemented in software. + It's not clear that the same is true for sparclet, although the docs + suggest it is. Rather than complicating things, the sparclet assembler + recognizes all v8 insns. */ +#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \ + | MASK_V9 | MASK_V9A | MASK_V9B) +#define sparclet (MASK_SPARCLET) +#define sparclite (MASK_SPARCLITE) +#define v9 (MASK_V9 | MASK_V9A | MASK_V9B) +#define v9a (MASK_V9A | MASK_V9B) +#define v9b (MASK_V9B) +/* v6 insns not supported by v9. */ +#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLET | MASK_SPARCLITE) +/* v9a instructions which would appear to be aliases to v9's impdep's + otherwise. */ +#define v9notv9a (MASK_V9) + +/* Table of opcode architectures. + The order is defined in opcode/sparc.h. */ + +static const struct sparc_opcode_arch sparc_opcode_archs[] = +{ + { "v6", MASK_V6 }, + { "v7", MASK_V6 | MASK_V7 }, + { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, + { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, + { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, + /* ??? Don't some v8 privileged insns conflict with v9? */ + { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, + /* v9 with ultrasparc additions */ + { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, + /* v9 with cheetah additions */ + { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B }, + { NULL, 0 } +}; + +/* Branch condition field. */ +#define COND(x) (((x) & 0xf) << 25) + +/* v9: Move (MOVcc and FMOVcc) condition field. */ +#define MCOND(x,i_or_f) ((((i_or_f) & 1) << 18) | (((x) >> 11) & (0xf << 14))) /* v9 */ + +/* v9: Move register (MOVRcc and FMOVRcc) condition field. */ +#define RCOND(x) (((x) & 0x7) << 10) /* v9 */ + +#define CONDA (COND (0x8)) +#define CONDCC (COND (0xd)) +#define CONDCS (COND (0x5)) +#define CONDE (COND (0x1)) +#define CONDG (COND (0xa)) +#define CONDGE (COND (0xb)) +#define CONDGU (COND (0xc)) +#define CONDL (COND (0x3)) +#define CONDLE (COND (0x2)) +#define CONDLEU (COND (0x4)) +#define CONDN (COND (0x0)) +#define CONDNE (COND (0x9)) +#define CONDNEG (COND (0x6)) +#define CONDPOS (COND (0xe)) +#define CONDVC (COND (0xf)) +#define CONDVS (COND (0x7)) + +#define CONDNZ CONDNE +#define CONDZ CONDE +#define CONDGEU CONDCC +#define CONDLU CONDCS + +#define FCONDA (COND (0x8)) +#define FCONDE (COND (0x9)) +#define FCONDG (COND (0x6)) +#define FCONDGE (COND (0xb)) +#define FCONDL (COND (0x4)) +#define FCONDLE (COND (0xd)) +#define FCONDLG (COND (0x2)) +#define FCONDN (COND (0x0)) +#define FCONDNE (COND (0x1)) +#define FCONDO (COND (0xf)) +#define FCONDU (COND (0x7)) +#define FCONDUE (COND (0xa)) +#define FCONDUG (COND (0x5)) +#define FCONDUGE (COND (0xc)) +#define FCONDUL (COND (0x3)) +#define FCONDULE (COND (0xe)) + +#define FCONDNZ FCONDNE +#define FCONDZ FCONDE + +#define ICC (0) /* v9 */ +#define XCC (1 << 12) /* v9 */ +#define FCC(x) (((x) & 0x3) << 11) /* v9 */ +#define FBFCC(x) (((x) & 0x3) << 20) /* v9 */ + +/* The order of the opcodes in the table is significant: + + * The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +/* Entries for commutative arithmetic operations. */ +/* ??? More entries can make use of this. */ +#define COMMUTEOP(opcode, op3, arch_mask) \ +{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } + +static const struct sparc_opcode sparc_opcodes[] = { + +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */ + +/* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the + 'ld' pseudo-op in v9. */ +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */ +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */ + +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */ + +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ + +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ + +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */ + +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */ +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */ + +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ + +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ + +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */ +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */ + +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */ +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */ + +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 }, +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */ +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */ +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */ +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 }, +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ + +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ + +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */ + +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ + +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 }, +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ + +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */ +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */ + +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */ +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 }, +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */ + +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */ + +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ + +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */ +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */ + +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ + +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 }, +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */ +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 }, +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */ +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */ + +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 }, +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */ +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */ + +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ + +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */ + +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ + +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */ +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */ + +{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, +{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 }, + +{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ +{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */ + +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 }, + +{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "allclean", F3(2, 0x31, 0)|RD(2), F3(~2, ~0x31, ~0)|RD(~2)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "otherw", F3(2, 0x31, 0)|RD(3), F3(~2, ~0x31, ~0)|RD(~3)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "normalw", F3(2, 0x31, 0)|RD(4), F3(~2, ~0x31, ~0)|RD(~4)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "invalw", F3(2, 0x31, 0)|RD(5), F3(~2, ~0x31, ~0)|RD(~5)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, + +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 }, +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 }, + +/* IFLUSH was renamed to FLUSH in v8. */ +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 }, + +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 }, +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 }, +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 }, + +{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 }, + +{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 }, +{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 }, + +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */ +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */ + +{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, + +{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, + +{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, + +{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite }, +{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite }, + +{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite }, +{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite }, + +{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 }, +{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 }, + +{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ +{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ + +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */ + +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */ + +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */ +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */ + +{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, + +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ +{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ + +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */ +{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */ +{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */ +{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ + +{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */ +{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */ +{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */ +{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */ +{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */ +{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */ + +{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */ +{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */ +{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */ +{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */ +{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */ +{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */ +{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */ +{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */ +{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */ +{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */ +{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */ +{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */ +{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */ +{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */ +{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */ +{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */ +{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */ +{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */ + +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */ +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ +{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */ +{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */ +{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */ +{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */ +{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */ +{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */ +{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */ + +{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ + +{ "rdhpr", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|SIMM13(~0), "$,d", 0, v9 }, /* rdhpr %hpriv,r */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0), "1,2,%", 0, v9 }, /* wrhpr r1,r2,%hpriv */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|SIMM13(~0), "1,%", 0, v9 }, /* wrhpr r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "1,i,%", 0, v9 }, /* wrhpr r1,i,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "i,1,%", F_ALIAS, v9 }, /* wrhpr i,r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RS1(~0), "i,%", 0, v9 }, /* wrhpr i,%hpriv */ + +/* ??? This group seems wrong. A three operand move? */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */ + +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ +{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */ +{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */ +{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */ + +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ + +{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, + +{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ +{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ + +/* This is not a commutative instruction. */ +{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, + +{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ +{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ + +{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ +{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ + +{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, + +{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, + +{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, +{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, + +{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, +{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, + +{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, + +{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, + +{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ +{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */ +{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ +{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */ +{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */ +{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */ +{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ +{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */ + +{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ +{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ + +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */ + +{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, + +{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, +{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, + +{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, +{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, + +{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, + +{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 }, + +{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 }, +{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 }, + +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 }, + + +/* Conditional instructions. + + Because this part of the table was such a mess earlier, I have + macrofied it so that all the branches and traps are generated from + a single-line description of each condition value. John Gilmore. */ + +/* Define branches -- one annulled, one without, etc. */ +#define br(opcode, mask, lose, flags) \ + { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \ + { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 } + +#define brx(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), "Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), ",T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a,T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20), ANNUL|BPRED|(lose), ",N Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|ANNUL, BPRED|(lose), ",a,N Z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), "z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), ",T z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a,T z,G", (flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose)|(2<<20), ",N z,G", (flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose)|(2<<20), ",a,N z,G", (flags), v9 } + +/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ +#define tr(opcode, mask, lose, flags) \ + { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \ + { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \ + { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \ + { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ + +/* v9: We must put `brx' before `br', to ensure that we never match something + v9: against an expression unless it is an expression. Otherwise, we end + v9: up with undefined symbol tables entries, because they get added, but + v9: are not deleted if the pattern fails to match. */ + +/* Define both branches and traps based on condition mask */ +#define cond(bop, top, mask, flags) \ + brx(bop, F2(0, 1)|(mask), F2(~0, ~1)|((~mask)&COND(~0)), F_DELAYED|(flags)), /* v9 */ \ + br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \ + tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), ((flags) & ~(F_UNBR|F_CONDBR))) + +/* Define all the conditions, all the branches, all the traps. */ + +/* Standard branch, trap mnemonics */ +cond ("b", "ta", CONDA, F_UNBR), +/* Alternative form (just for assembly, not for disassembly) */ +cond ("ba", "t", CONDA, F_UNBR|F_ALIAS), + +cond ("bcc", "tcc", CONDCC, F_CONDBR), +cond ("bcs", "tcs", CONDCS, F_CONDBR), +cond ("be", "te", CONDE, F_CONDBR), +cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS), +cond ("bg", "tg", CONDG, F_CONDBR), +cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), +cond ("bge", "tge", CONDGE, F_CONDBR), +cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ +cond ("bgu", "tgu", CONDGU, F_CONDBR), +cond ("bl", "tl", CONDL, F_CONDBR), +cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), +cond ("ble", "tle", CONDLE, F_CONDBR), +cond ("bleu", "tleu", CONDLEU, F_CONDBR), +cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ +cond ("bn", "tn", CONDN, F_CONDBR), +cond ("bne", "tne", CONDNE, F_CONDBR), +cond ("bneg", "tneg", CONDNEG, F_CONDBR), +cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */ +cond ("bpos", "tpos", CONDPOS, F_CONDBR), +cond ("bvc", "tvc", CONDVC, F_CONDBR), +cond ("bvs", "tvs", CONDVS, F_CONDBR), +cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ + +#undef cond +#undef br +#undef brr /* v9 */ +#undef tr + +#define brr(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|BPRED, ANNUL|(lose), "1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose), ",T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a,T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose), ",N 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose), ",a,N 1,k", F_DELAYED|(flags), v9 } + +#define condr(bop, mask, flags) /* v9 */ \ + brr(bop, F2(0, 3)|COND(mask), F2(~0, ~3)|COND(~(mask)), (flags)) /* v9 */ + +/* v9 */ condr("brnz", 0x5, F_CONDBR), +/* v9 */ condr("brz", 0x1, F_CONDBR), +/* v9 */ condr("brgez", 0x7, F_CONDBR), +/* v9 */ condr("brlz", 0x3, F_CONDBR), +/* v9 */ condr("brlez", 0x2, F_CONDBR), +/* v9 */ condr("brgz", 0x6, F_CONDBR), + +#undef condr /* v9 */ +#undef brr /* v9 */ + +#define movr(opcode, mask, flags) /* v9 */ \ + { opcode, F3(2, 0x2f, 0)|RCOND(mask), F3(~2, ~0x2f, ~0)|RCOND(~(mask)), "1,2,d", (flags), v9 }, \ + { opcode, F3(2, 0x2f, 1)|RCOND(mask), F3(~2, ~0x2f, ~1)|RCOND(~(mask)), "1,j,d", (flags), v9 } + +#define fmrrs(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,f,g", (flags) | F_FLOAT, v9 } +#define fmrrd(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,B,H", (flags) | F_FLOAT, v9 } +#define fmrrq(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,R,J", (flags) | F_FLOAT, v9 } + +#define fmovrs(mop, mask, flags) /* v9 */ \ + fmrrs(mop, F3(2, 0x35, 0)|OPF_LOW5(5)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~5)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrd(mop, mask, flags) /* v9 */ \ + fmrrd(mop, F3(2, 0x35, 0)|OPF_LOW5(6)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~6)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrq(mop, mask, flags) /* v9 */ \ + fmrrq(mop, F3(2, 0x35, 0)|OPF_LOW5(7)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~7)|RCOND(~(mask)), (flags)) /* v9 */ + +/* v9 */ movr("movrne", 0x5, 0), +/* v9 */ movr("movre", 0x1, 0), +/* v9 */ movr("movrgez", 0x7, 0), +/* v9 */ movr("movrlz", 0x3, 0), +/* v9 */ movr("movrlez", 0x2, 0), +/* v9 */ movr("movrgz", 0x6, 0), +/* v9 */ movr("movrnz", 0x5, F_ALIAS), +/* v9 */ movr("movrz", 0x1, F_ALIAS), + +/* v9 */ fmovrs("fmovrsne", 0x5, 0), +/* v9 */ fmovrs("fmovrse", 0x1, 0), +/* v9 */ fmovrs("fmovrsgez", 0x7, 0), +/* v9 */ fmovrs("fmovrslz", 0x3, 0), +/* v9 */ fmovrs("fmovrslez", 0x2, 0), +/* v9 */ fmovrs("fmovrsgz", 0x6, 0), +/* v9 */ fmovrs("fmovrsnz", 0x5, F_ALIAS), +/* v9 */ fmovrs("fmovrsz", 0x1, F_ALIAS), + +/* v9 */ fmovrd("fmovrdne", 0x5, 0), +/* v9 */ fmovrd("fmovrde", 0x1, 0), +/* v9 */ fmovrd("fmovrdgez", 0x7, 0), +/* v9 */ fmovrd("fmovrdlz", 0x3, 0), +/* v9 */ fmovrd("fmovrdlez", 0x2, 0), +/* v9 */ fmovrd("fmovrdgz", 0x6, 0), +/* v9 */ fmovrd("fmovrdnz", 0x5, F_ALIAS), +/* v9 */ fmovrd("fmovrdz", 0x1, F_ALIAS), + +/* v9 */ fmovrq("fmovrqne", 0x5, 0), +/* v9 */ fmovrq("fmovrqe", 0x1, 0), +/* v9 */ fmovrq("fmovrqgez", 0x7, 0), +/* v9 */ fmovrq("fmovrqlz", 0x3, 0), +/* v9 */ fmovrq("fmovrqlez", 0x2, 0), +/* v9 */ fmovrq("fmovrqgz", 0x6, 0), +/* v9 */ fmovrq("fmovrqnz", 0x5, F_ALIAS), +/* v9 */ fmovrq("fmovrqz", 0x1, F_ALIAS), + +#undef movr /* v9 */ +#undef fmovr /* v9 */ +#undef fmrr /* v9 */ + +#define movicc(opcode, cond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|XCC|(1<<11), "z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|XCC|(1<<11), "z,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|(1<<11), "Z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|(1<<11), "Z,I,d", flags, v9 } + +#define movfcc(opcode, fcond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~0), "6,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~1), "6,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~0), "7,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~1), "7,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~0), "8,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~1), "8,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~0), "9,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~1), "9,I,d", flags, v9 } + +#define movcc(opcode, cond, fcond, flags) /* v9 */ \ + movfcc (opcode, fcond, flags), /* v9 */ \ + movicc (opcode, cond, flags) /* v9 */ + +/* v9 */ movcc ("mova", CONDA, FCONDA, 0), +/* v9 */ movicc ("movcc", CONDCC, 0), +/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS), +/* v9 */ movicc ("movcs", CONDCS, 0), +/* v9 */ movicc ("movlu", CONDLU, F_ALIAS), +/* v9 */ movcc ("move", CONDE, FCONDE, 0), +/* v9 */ movcc ("movg", CONDG, FCONDG, 0), +/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0), +/* v9 */ movicc ("movgu", CONDGU, 0), +/* v9 */ movcc ("movl", CONDL, FCONDL, 0), +/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0), +/* v9 */ movicc ("movleu", CONDLEU, 0), +/* v9 */ movfcc ("movlg", FCONDLG, 0), +/* v9 */ movcc ("movn", CONDN, FCONDN, 0), +/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0), +/* v9 */ movicc ("movneg", CONDNEG, 0), +/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ movfcc ("movo", FCONDO, 0), +/* v9 */ movicc ("movpos", CONDPOS, 0), +/* v9 */ movfcc ("movu", FCONDU, 0), +/* v9 */ movfcc ("movue", FCONDUE, 0), +/* v9 */ movfcc ("movug", FCONDUG, 0), +/* v9 */ movfcc ("movuge", FCONDUGE, 0), +/* v9 */ movfcc ("movul", FCONDUL, 0), +/* v9 */ movfcc ("movule", FCONDULE, 0), +/* v9 */ movicc ("movvc", CONDVC, 0), +/* v9 */ movicc ("movvs", CONDVS, 0), +/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS), + +#undef movicc /* v9 */ +#undef movfcc /* v9 */ +#undef movcc /* v9 */ + +#define FM_SF 1 /* v9 - values for fpsize */ +#define FM_DF 2 /* v9 */ +#define FM_QF 3 /* v9 */ + +#define fmoviccx(opcode, fpsize, args, cond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags, v9 } + +#define fmovfccx(opcode, fpsize, args, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags, v9 } + +/* FIXME: use fmovicc/fmovfcc? */ /* v9 */ +#define fmovccx(opcode, fpsize, args, cond, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags | F_FLOAT, v9 } + +#define fmovicc(suffix, cond, flags) /* v9 */ \ +fmoviccx("fmovd" suffix, FM_DF, "B,H", cond, flags), \ +fmoviccx("fmovq" suffix, FM_QF, "R,J", cond, flags), \ +fmoviccx("fmovs" suffix, FM_SF, "f,g", cond, flags) + +#define fmovfcc(suffix, fcond, flags) /* v9 */ \ +fmovfccx("fmovd" suffix, FM_DF, "B,H", fcond, flags), \ +fmovfccx("fmovq" suffix, FM_QF, "R,J", fcond, flags), \ +fmovfccx("fmovs" suffix, FM_SF, "f,g", fcond, flags) + +#define fmovcc(suffix, cond, fcond, flags) /* v9 */ \ +fmovccx("fmovd" suffix, FM_DF, "B,H", cond, fcond, flags), \ +fmovccx("fmovq" suffix, FM_QF, "R,J", cond, fcond, flags), \ +fmovccx("fmovs" suffix, FM_SF, "f,g", cond, fcond, flags) + +/* v9 */ fmovcc ("a", CONDA, FCONDA, 0), +/* v9 */ fmovicc ("cc", CONDCC, 0), +/* v9 */ fmovicc ("cs", CONDCS, 0), +/* v9 */ fmovcc ("e", CONDE, FCONDE, 0), +/* v9 */ fmovcc ("g", CONDG, FCONDG, 0), +/* v9 */ fmovcc ("ge", CONDGE, FCONDGE, 0), +/* v9 */ fmovicc ("geu", CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("gu", CONDGU, 0), +/* v9 */ fmovcc ("l", CONDL, FCONDL, 0), +/* v9 */ fmovcc ("le", CONDLE, FCONDLE, 0), +/* v9 */ fmovicc ("leu", CONDLEU, 0), +/* v9 */ fmovfcc ("lg", FCONDLG, 0), +/* v9 */ fmovicc ("lu", CONDLU, F_ALIAS), +/* v9 */ fmovcc ("n", CONDN, FCONDN, 0), +/* v9 */ fmovcc ("ne", CONDNE, FCONDNE, 0), +/* v9 */ fmovicc ("neg", CONDNEG, 0), +/* v9 */ fmovcc ("nz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovfcc ("o", FCONDO, 0), +/* v9 */ fmovicc ("pos", CONDPOS, 0), +/* v9 */ fmovfcc ("u", FCONDU, 0), +/* v9 */ fmovfcc ("ue", FCONDUE, 0), +/* v9 */ fmovfcc ("ug", FCONDUG, 0), +/* v9 */ fmovfcc ("uge", FCONDUGE, 0), +/* v9 */ fmovfcc ("ul", FCONDUL, 0), +/* v9 */ fmovfcc ("ule", FCONDULE, 0), +/* v9 */ fmovicc ("vc", CONDVC, 0), +/* v9 */ fmovicc ("vs", CONDVS, 0), +/* v9 */ fmovcc ("z", CONDZ, FCONDZ, F_ALIAS), + +#undef fmoviccx /* v9 */ +#undef fmovfccx /* v9 */ +#undef fmovccx /* v9 */ +#undef fmovicc /* v9 */ +#undef fmovfcc /* v9 */ +#undef fmovcc /* v9 */ +#undef FM_DF /* v9 */ +#undef FM_QF /* v9 */ +#undef FM_SF /* v9 */ + +/* Coprocessor branches. */ +#define CBR(opcode, mask, lose, flags, arch) \ + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED, arch }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED, arch } + +/* Floating point branches. */ +#define FBR(opcode, mask, lose, flags) \ + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED | F_FBR, v6 }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED | F_FBR, v6 } + +/* V9 extended floating point branches. */ +#define FBRX(opcode, mask, lose, flags) /* v9 */ \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a,T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask), ANNUL|BPRED|FBFCC(~0)|(lose), ",N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|ANNUL, BPRED|FBFCC(~0)|(lose), ",a,N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), "7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), ",T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a,T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask), ANNUL|BPRED|FBFCC(~1)|(lose), ",N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|ANNUL, BPRED|FBFCC(~1)|(lose), ",a,N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), "8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), ",T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a,T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask), ANNUL|BPRED|FBFCC(~2)|(lose), ",N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|ANNUL, BPRED|FBFCC(~2)|(lose), ",a,N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), "9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), ",T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 } + +/* v9: We must put `FBRX' before `FBR', to ensure that we never match + v9: something against an expression unless it is an expression. Otherwise, + v9: we end up with undefined symbol tables entries, because they get added, + v9: but are not deleted if the pattern fails to match. */ + +#define CONDFC(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet) + +#define CONDFCL(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6) + +#define CONDF(fop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) + +CONDFC ("fb", "cb", 0x8, F_UNBR), +CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS), +CONDFC ("fbe", "cb0", 0x9, F_CONDBR), +CONDF ("fbz", 0x9, F_CONDBR|F_ALIAS), +CONDFC ("fbg", "cb2", 0x6, F_CONDBR), +CONDFC ("fbge", "cb02", 0xb, F_CONDBR), +CONDFC ("fbl", "cb1", 0x4, F_CONDBR), +CONDFC ("fble", "cb01", 0xd, F_CONDBR), +CONDFC ("fblg", "cb12", 0x2, F_CONDBR), +CONDFCL ("fbn", "cbn", 0x0, F_UNBR), +CONDFC ("fbne", "cb123", 0x1, F_CONDBR), +CONDF ("fbnz", 0x1, F_CONDBR|F_ALIAS), +CONDFC ("fbo", "cb012", 0xf, F_CONDBR), +CONDFC ("fbu", "cb3", 0x7, F_CONDBR), +CONDFC ("fbue", "cb03", 0xa, F_CONDBR), +CONDFC ("fbug", "cb23", 0x5, F_CONDBR), +CONDFC ("fbuge", "cb023", 0xc, F_CONDBR), +CONDFC ("fbul", "cb13", 0x3, F_CONDBR), +CONDFC ("fbule", "cb013", 0xe, F_CONDBR), + +#undef CONDFC +#undef CONDFCL +#undef CONDF +#undef CBR +#undef FBR +#undef FBRX /* v9 */ + +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */ + +{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ + +{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 }, +{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 }, + +{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, + +{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, + +{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, + +{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 }, +{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 }, + +/* This *is* a commutative instruction. */ +{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, +/* This *is* a commutative instruction. */ +{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, +{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, + +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ + +{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ +{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ + +/* FPop1 and FPop2 are not instructions. Don't accept them. */ + +{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, + +{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,H", F_FLOAT, v9 }, +{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,H", F_FLOAT, v9 }, + +{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "B,g", F_FLOAT, v9 }, +{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "B,J", F_FLOAT, v9 }, + +{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, +{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 }, +{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 }, +{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 }, +{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 }, +{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 }, +{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 }, +{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 }, +{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 }, + +{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 }, +{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 }, + +{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 }, +{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 }, +{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 }, + +{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 }, + +{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 }, +{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 }, +{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 }, +{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 }, +{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 }, +{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 }, + +#define CMPFCC(x) (((x)&0x3)<<25) + +{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 }, +{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 }, +{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 }, +{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 }, +{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 }, +{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 }, + +/* These Extended FPop (FIFO) instructions are new in the Fujitsu + MB86934, replacing the CPop instructions from v6 and later + processors. */ + +#define EFPOP1_2(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op)|RS1_G0, args, 0, sparclite } +#define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op), args, 0, sparclite } +#define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0, args, 0, sparclite } + +EFPOP1_2 ("efitod", 0x0c8, "f,H"), +EFPOP1_2 ("efitos", 0x0c4, "f,g"), +EFPOP1_2 ("efdtoi", 0x0d2, "B,g"), +EFPOP1_2 ("efstoi", 0x0d1, "f,g"), +EFPOP1_2 ("efstod", 0x0c9, "f,H"), +EFPOP1_2 ("efdtos", 0x0c6, "B,g"), +EFPOP1_2 ("efmovs", 0x001, "f,g"), +EFPOP1_2 ("efnegs", 0x005, "f,g"), +EFPOP1_2 ("efabss", 0x009, "f,g"), +EFPOP1_2 ("efsqrtd", 0x02a, "B,H"), +EFPOP1_2 ("efsqrts", 0x029, "f,g"), +EFPOP1_3 ("efaddd", 0x042, "v,B,H"), +EFPOP1_3 ("efadds", 0x041, "e,f,g"), +EFPOP1_3 ("efsubd", 0x046, "v,B,H"), +EFPOP1_3 ("efsubs", 0x045, "e,f,g"), +EFPOP1_3 ("efdivd", 0x04e, "v,B,H"), +EFPOP1_3 ("efdivs", 0x04d, "e,f,g"), +EFPOP1_3 ("efmuld", 0x04a, "v,B,H"), +EFPOP1_3 ("efmuls", 0x049, "e,f,g"), +EFPOP1_3 ("efsmuld", 0x069, "e,f,H"), +EFPOP2_2 ("efcmpd", 0x052, "v,B"), +EFPOP2_2 ("efcmped", 0x056, "v,B"), +EFPOP2_2 ("efcmps", 0x051, "e,f"), +EFPOP2_2 ("efcmpes", 0x055, "e,f"), + +#undef EFPOP1_2 +#undef EFPOP1_3 +#undef EFPOP2_2 + +/* These are marked F_ALIAS, so that they won't conflict with sparclite insns + present. Otherwise, the F_ALIAS flag is ignored. */ +{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 }, +{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 }, + +/* sparclet specific insns */ + +COMMUTEOP ("umac", 0x3e, sparclet), +COMMUTEOP ("smac", 0x3f, sparclet), +COMMUTEOP ("umacd", 0x2e, sparclet), +COMMUTEOP ("smacd", 0x2f, sparclet), +COMMUTEOP ("umuld", 0x09, sparclet), +COMMUTEOP ("smuld", 0x0d, sparclet), + +{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet }, +{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet }, + +/* The manual isn't completely accurate on these insns. The `rs2' field is + treated as being 6 bits to account for 6 bit immediates to cpush. It is + assumed that it is intended that bit 5 is 0 when rs2 contains a reg. */ +#define BIT5 (1<<5) +{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet }, +{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet }, +{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet }, +{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet }, +#undef BIT5 + +/* sparclet coprocessor branch insns */ +#define SLCBCC2(opcode, mask, lose) \ + { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR, sparclet }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet } +#define SLCBCC(opcode, mask) \ + SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask))) + +/* cbn,cba can't be defined here because they're defined elsewhere and GAS + requires all mnemonics of the same name to be consecutive. */ +/*SLCBCC("cbn", 0), - already defined */ +SLCBCC("cbe", 1), +SLCBCC("cbf", 2), +SLCBCC("cbef", 3), +SLCBCC("cbr", 4), +SLCBCC("cber", 5), +SLCBCC("cbfr", 6), +SLCBCC("cbefr", 7), +/*SLCBCC("cba", 8), - already defined */ +SLCBCC("cbne", 9), +SLCBCC("cbnf", 10), +SLCBCC("cbnef", 11), +SLCBCC("cbnr", 12), +SLCBCC("cbner", 13), +SLCBCC("cbnfr", 14), +SLCBCC("cbnefr", 15), + +#undef SLCBCC2 +#undef SLCBCC + +{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 }, +{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 }, + +/* v9 synthetic insns */ +{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */ +{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */ +{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */ +{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */ +{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */ + +/* Ultrasparc extensions */ +{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a }, + +/* FIXME: Do we want to mark these as F_FLOAT, or something similar? */ +{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a }, +{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a }, +{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a }, +{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a }, +{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a }, +{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a }, +{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a }, +{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a }, + +{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a }, +{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a }, +{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a }, +{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a }, +{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a }, + +/* Note that the mixing of 32/64 bit regs is intentional. */ +{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a }, +{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a }, +{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a }, +{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a }, +{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a }, +{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a }, +{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a }, + +{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a }, +{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a }, +{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a }, + +{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a }, +{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a }, +{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a }, +{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a }, +{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a }, +{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a }, +{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a }, +{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a }, +{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a }, +{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a }, +{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a }, +{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a }, +{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a }, +{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a }, +{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a }, +{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a }, +{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a }, +{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a }, +{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a }, +{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a }, +{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a }, +{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a }, +{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a }, +{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a }, +{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a }, +{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a }, +{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a }, +{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a }, +{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a }, +{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a }, +{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a }, +{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a }, + +{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a }, +{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a }, +{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a }, +{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a }, +{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a }, +{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a }, +{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a }, +{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a }, + +{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a }, +{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a }, +{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a }, +{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a }, +{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a }, +{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a }, + +{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a }, + +{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a }, +{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a }, +{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a }, + +/* Cheetah instructions */ +{ "edge8n", F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b }, +{ "edge8ln", F3F(2, 0x36, 0x003), F3F(~2, ~0x36, ~0x003), "1,2,d", 0, v9b }, +{ "edge16n", F3F(2, 0x36, 0x005), F3F(~2, ~0x36, ~0x005), "1,2,d", 0, v9b }, +{ "edge16ln", F3F(2, 0x36, 0x007), F3F(~2, ~0x36, ~0x007), "1,2,d", 0, v9b }, +{ "edge32n", F3F(2, 0x36, 0x009), F3F(~2, ~0x36, ~0x009), "1,2,d", 0, v9b }, +{ "edge32ln", F3F(2, 0x36, 0x00b), F3F(~2, ~0x36, ~0x00b), "1,2,d", 0, v9b }, + +{ "bmask", F3F(2, 0x36, 0x019), F3F(~2, ~0x36, ~0x019), "1,2,d", 0, v9b }, +{ "bshuffle", F3F(2, 0x36, 0x04c), F3F(~2, ~0x36, ~0x04c), "v,B,H", 0, v9b }, + +{ "siam", F3F(2, 0x36, 0x081), F3F(~2, ~0x36, ~0x081)|RD_G0|RS1_G0|RS2(~7), "3", 0, v9b }, + +/* More v9 specific insns, these need to come last so they do not clash + with v9a instructions such as "edge8" which looks like impdep1. */ + +#define IMPDEP(name, code) \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,e,f,g", 0, v9notv9a } + +IMPDEP ("impdep1", 0x36), +IMPDEP ("impdep2", 0x37), + +#undef IMPDEP + +}; + +static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); + +/* Utilities for argument parsing. */ + +typedef struct +{ + int value; + const char *name; +} arg; + +/* Look up VALUE in TABLE. */ + +static const char * +lookup_value (const arg *table, int value) +{ + const arg *p; + + for (p = table; p->name; ++p) + if (value == p->value) + return p->name; + + return NULL; +} + +/* Handle ASI's. */ + +static const arg asi_table_v8[] = +{ + { 0x00, "#ASI_M_RES00" }, + { 0x01, "#ASI_M_UNA01" }, + { 0x02, "#ASI_M_MXCC" }, + { 0x03, "#ASI_M_FLUSH_PROBE" }, + { 0x04, "#ASI_M_MMUREGS" }, + { 0x05, "#ASI_M_TLBDIAG" }, + { 0x06, "#ASI_M_DIAGS" }, + { 0x07, "#ASI_M_IODIAG" }, + { 0x08, "#ASI_M_USERTXT" }, + { 0x09, "#ASI_M_KERNELTXT" }, + { 0x0A, "#ASI_M_USERDATA" }, + { 0x0B, "#ASI_M_KERNELDATA" }, + { 0x0C, "#ASI_M_TXTC_TAG" }, + { 0x0D, "#ASI_M_TXTC_DATA" }, + { 0x0E, "#ASI_M_DATAC_TAG" }, + { 0x0F, "#ASI_M_DATAC_DATA" }, + { 0x10, "#ASI_M_FLUSH_PAGE" }, + { 0x11, "#ASI_M_FLUSH_SEG" }, + { 0x12, "#ASI_M_FLUSH_REGION" }, + { 0x13, "#ASI_M_FLUSH_CTX" }, + { 0x14, "#ASI_M_FLUSH_USER" }, + { 0x17, "#ASI_M_BCOPY" }, + { 0x18, "#ASI_M_IFLUSH_PAGE" }, + { 0x19, "#ASI_M_IFLUSH_SEG" }, + { 0x1A, "#ASI_M_IFLUSH_REGION" }, + { 0x1B, "#ASI_M_IFLUSH_CTX" }, + { 0x1C, "#ASI_M_IFLUSH_USER" }, + { 0x1F, "#ASI_M_BFILL" }, + { 0x20, "#ASI_M_BYPASS" }, + { 0x29, "#ASI_M_FBMEM" }, + { 0x2A, "#ASI_M_VMEUS" }, + { 0x2B, "#ASI_M_VMEPS" }, + { 0x2C, "#ASI_M_VMEUT" }, + { 0x2D, "#ASI_M_VMEPT" }, + { 0x2E, "#ASI_M_SBUS" }, + { 0x2F, "#ASI_M_CTL" }, + { 0x31, "#ASI_M_FLUSH_IWHOLE" }, + { 0x36, "#ASI_M_IC_FLCLEAR" }, + { 0x37, "#ASI_M_DC_FLCLEAR" }, + { 0x39, "#ASI_M_DCDR" }, + { 0x40, "#ASI_M_VIKING_TMP1" }, + { 0x41, "#ASI_M_VIKING_TMP2" }, + { 0x4c, "#ASI_M_ACTION" }, + { 0, NULL } +}; + +static const arg asi_table_v9[] = +{ + /* These are in the v9 architecture manual. */ + /* The shorter versions appear first, they're here because Sun's as has them. + Sun's as uses #ASI_P_L instead of #ASI_PL (which appears in the + UltraSPARC architecture manual). */ + { 0x04, "#ASI_N" }, + { 0x0c, "#ASI_N_L" }, + { 0x10, "#ASI_AIUP" }, + { 0x11, "#ASI_AIUS" }, + { 0x18, "#ASI_AIUP_L" }, + { 0x19, "#ASI_AIUS_L" }, + { 0x80, "#ASI_P" }, + { 0x81, "#ASI_S" }, + { 0x82, "#ASI_PNF" }, + { 0x83, "#ASI_SNF" }, + { 0x88, "#ASI_P_L" }, + { 0x89, "#ASI_S_L" }, + { 0x8a, "#ASI_PNF_L" }, + { 0x8b, "#ASI_SNF_L" }, + { 0x04, "#ASI_NUCLEUS" }, + { 0x0c, "#ASI_NUCLEUS_LITTLE" }, + { 0x10, "#ASI_AS_IF_USER_PRIMARY" }, + { 0x11, "#ASI_AS_IF_USER_SECONDARY" }, + { 0x18, "#ASI_AS_IF_USER_PRIMARY_LITTLE" }, + { 0x19, "#ASI_AS_IF_USER_SECONDARY_LITTLE" }, + { 0x80, "#ASI_PRIMARY" }, + { 0x81, "#ASI_SECONDARY" }, + { 0x82, "#ASI_PRIMARY_NOFAULT" }, + { 0x83, "#ASI_SECONDARY_NOFAULT" }, + { 0x88, "#ASI_PRIMARY_LITTLE" }, + { 0x89, "#ASI_SECONDARY_LITTLE" }, + { 0x8a, "#ASI_PRIMARY_NOFAULT_LITTLE" }, + { 0x8b, "#ASI_SECONDARY_NOFAULT_LITTLE" }, + /* These are UltraSPARC extensions. */ + /* FIXME: There are dozens of them. Not sure we want them all. + Most are for kernel building but some are for vis type stuff. */ + { 0, NULL } +}; + +/* Return the name for ASI value VALUE or NULL if not found. */ + +static const char * +sparc_decode_asi_v9 (int value) +{ + return lookup_value (asi_table_v9, value); +} + +static const char * +sparc_decode_asi_v8 (int value) +{ + return lookup_value (asi_table_v8, value); +} + +/* Handle membar masks. */ + +static const arg membar_table[] = +{ + { 0x40, "#Sync" }, + { 0x20, "#MemIssue" }, + { 0x10, "#Lookaside" }, + { 0x08, "#StoreStore" }, + { 0x04, "#LoadStore" }, + { 0x02, "#StoreLoad" }, + { 0x01, "#LoadLoad" }, + { 0, NULL } +}; + +/* Return the name for membar value VALUE or NULL if not found. */ + +static const char * +sparc_decode_membar (int value) +{ + return lookup_value (membar_table, value); +} + +/* Handle prefetch args. */ + +static const arg prefetch_table[] = +{ + { 0, "#n_reads" }, + { 1, "#one_read" }, + { 2, "#n_writes" }, + { 3, "#one_write" }, + { 4, "#page" }, + { 16, "#invalidate" }, + { 0, NULL } +}; + +/* Return the name for prefetch value VALUE or NULL if not found. */ + +static const char * +sparc_decode_prefetch (int value) +{ + return lookup_value (prefetch_table, value); +} + +/* Handle sparclet coprocessor registers. */ + +static const arg sparclet_cpreg_table[] = +{ + { 0, "%ccsr" }, + { 1, "%ccfr" }, + { 2, "%cccrcr" }, + { 3, "%ccpr" }, + { 4, "%ccsr2" }, + { 5, "%cccrr" }, + { 6, "%ccrstr" }, + { 0, NULL } +}; + +/* Return the name for sparclet cpreg value VALUE or NULL if not found. */ + +static const char * +sparc_decode_sparclet_cpreg (int value) +{ + return lookup_value (sparclet_cpreg_table, value); +} + +#undef MASK_V9 + +/* opcodes/sparc-dis.c */ + +/* Print SPARC instructions. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Bitmask of v9 architectures. */ +#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ + | (1 << SPARC_OPCODE_ARCH_V9A) \ + | (1 << SPARC_OPCODE_ARCH_V9B)) +/* 1 if INSN is for v9 only. */ +#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9)) +/* 1 if INSN is for v9. */ +#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0) + +/* The sorted opcode table. */ +static const sparc_opcode **sorted_opcodes; + +/* For faster lookup, after insns are sorted they are hashed. */ +/* ??? I think there is room for even more improvement. */ + +#define HASH_SIZE 256 +/* It is important that we only look at insn code bits as that is how the + opcode table is hashed. OPCODE_BITS is a table of valid bits for each + of the main types (0,1,2,3). */ +static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; +#define HASH_INSN(INSN) \ + ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) +typedef struct sparc_opcode_hash +{ + struct sparc_opcode_hash *next; + const sparc_opcode *opcode; +} sparc_opcode_hash; + +static sparc_opcode_hash *opcode_hash_table[HASH_SIZE]; + +/* Sign-extend a value which is N bits long. */ +#define SEX(value, bits) \ + ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ + >> ((8 * sizeof (int)) - bits) ) + +static const char * const reg_names[] = +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", + "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", + "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", + "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", +/* psr, wim, tbr, fpsr, cpsr are v8 only. */ + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" +}; + +#define freg_names (®_names[4 * 8]) + +/* These are ordered according to there register number in + rdpr and wrpr insns. */ +static const char * const v9_priv_reg_names[] = +{ + "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", + "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", + "wstate", "fq", "gl" + /* "ver" - special cased */ +}; + +/* These are ordered according to there register number in + rdhpr and wrhpr insns. */ +static const char * const v9_hpriv_reg_names[] = +{ + "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver", + "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13", + "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20", + "resv21", "resv22", "resv23", "resv24", "resv25", "resv26", "resv27", + "resv28", "resv29", "resv30", "hstick_cmpr" +}; + +/* These are ordered according to there register number in + rd and wr insns (-16). */ +static const char * const v9a_asr_reg_names[] = +{ + "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint", + "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr" +}; + +/* Macros used to extract instruction fields. Not all fields have + macros defined here, only those which are actually used. */ + +#define X_RD(i) (((i) >> 25) & 0x1f) +#define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_LDST_I(i) (((i) >> 13) & 1) +#define X_ASI(i) (((i) >> 5) & 0xff) +#define X_RS2(i) (((i) >> 0) & 0x1f) +#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) +#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) +#define X_DISP22(i) (((i) >> 0) & 0x3fffff) +#define X_IMM22(i) X_DISP22 (i) +#define X_DISP30(i) (((i) >> 0) & 0x3fffffff) + +/* These are for v9. */ +#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) +#define X_DISP19(i) (((i) >> 0) & 0x7ffff) +#define X_MEMBAR(i) ((i) & 0x7f) + +/* Here is the union which was used to extract instruction fields + before the shift and mask macros were written. + + union sparc_insn + { + unsigned long int code; + struct + { + unsigned int anop:2; + #define op ldst.anop + unsigned int anrd:5; + #define rd ldst.anrd + unsigned int op3:6; + unsigned int anrs1:5; + #define rs1 ldst.anrs1 + unsigned int i:1; + unsigned int anasi:8; + #define asi ldst.anasi + unsigned int anrs2:5; + #define rs2 ldst.anrs2 + #define shcnt rs2 + } ldst; + struct + { + unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; + unsigned int IMM13:13; + #define imm13 IMM13.IMM13 + } IMM13; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; + #define disp22 branch.DISP22 + #define imm22 disp22 + } branch; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int z:1; + unsigned int rcond:3; + unsigned int op2:3; + unsigned int DISP16HI:2; + unsigned int p:1; + unsigned int _rs1:5; + unsigned int DISP16LO:14; + } branch16; + struct + { + unsigned int anop:2; + unsigned int adisp30:30; + #define disp30 call.adisp30 + } call; + }; */ + +/* Nonzero if INSN is the opcode for a delayed branch. */ + +static int +is_delayed_branch (unsigned long insn) +{ + sparc_opcode_hash *op; + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const sparc_opcode *opcode = op->opcode; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + return opcode->flags & F_DELAYED; + } + return 0; +} + +/* extern void qsort (); */ + +/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value + to compare_opcodes. */ +static unsigned int current_arch_mask; + +/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ + +static int +compute_arch_mask (unsigned long mach) +{ + switch (mach) + { + case 0 : + case bfd_mach_sparc : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); + case bfd_mach_sparc_sparclet : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); + case bfd_mach_sparc_sparclite : + case bfd_mach_sparc_sparclite_le : + /* sparclites insns are recognized by default (because that's how + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ + return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + case bfd_mach_sparc_v8plus : + case bfd_mach_sparc_v9 : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); + case bfd_mach_sparc_v8plusa : + case bfd_mach_sparc_v9a : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); + case bfd_mach_sparc_v8plusb : + case bfd_mach_sparc_v9b : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); + } + abort (); +} + +/* Compare opcodes A and B. */ + +static int +compare_opcodes (const void * a, const void * b) +{ + sparc_opcode *op0 = * (sparc_opcode **) a; + sparc_opcode *op1 = * (sparc_opcode **) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; + + /* If one (and only one) insn isn't supported by the current architecture, + prefer the one that is. If neither are supported, but they're both for + the same architecture, continue processing. Otherwise (both unsupported + and for different architectures), prefer lower numbered arch's (fudged + by comparing the bitmasks). */ + if (op0->architecture & current_arch_mask) + { + if (! (op1->architecture & current_arch_mask)) + return -1; + } + else + { + if (op1->architecture & current_arch_mask) + return 1; + else if (op0->architecture != op1->architecture) + return op0->architecture - op1->architecture; + } + + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } + + if (match1 & lose1) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } + + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ + + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); + + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } + + /* Except for aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + i = strcmp (op0->name, op1->name); + if (i) + { + if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ + return i; + else + fprintf (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), + op0->name, op1->name); + } + + /* Fewer arguments are preferred. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) strchr (op0->args, '+'); + char *p1 = (char *) strchr (op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* Put 1,i before i,1. */ + { + int i0 = strncmp (op0->args, "i,1", 3) == 0; + int i1 = strncmp (op1->args, "i,1", 3) == 0; + + if (i0 ^ i1) + return i0 - i1; + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + /* ??? This is no longer true now that we sort a vector of pointers, + not the table itself. */ + return 0; +} + +/* Build a hash table from the opcode table. + OPCODE_TABLE is a sorted list of pointers into the opcode table. */ + +static void +build_hash_table (const sparc_opcode **opcode_table, + sparc_opcode_hash **hash_table, + int num_opcodes) +{ + int i; + int hash_count[HASH_SIZE]; + static sparc_opcode_hash *hash_buf = NULL; + + /* Start at the end of the table and work backwards so that each + chain is sorted. */ + + memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); + memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); + if (hash_buf != NULL) + free (hash_buf); + hash_buf = malloc (sizeof (* hash_buf) * num_opcodes); + for (i = num_opcodes - 1; i >= 0; --i) + { + int hash = HASH_INSN (opcode_table[i]->match); + sparc_opcode_hash *h = &hash_buf[i]; + + h->next = hash_table[hash]; + h->opcode = opcode_table[i]; + hash_table[hash] = h; + ++hash_count[hash]; + } + +#if 0 /* for debugging */ + { + int min_count = num_opcodes, max_count = 0; + int total; + + for (i = 0; i < HASH_SIZE; ++i) + { + if (hash_count[i] < min_count) + min_count = hash_count[i]; + if (hash_count[i] > max_count) + max_count = hash_count[i]; + total += hash_count[i]; + } + + printf ("Opcode hash table stats: min %d, max %d, ave %f\n", + min_count, max_count, (double) total / HASH_SIZE); + } +#endif +} + +/* Print one instruction from MEMADDR on INFO->STREAM. + + We suffix the instruction with a comment that gives the absolute + address involved, as well as its symbolic form, if the instruction + is preceded by a findable `sethi' and it either adds an immediate + displacement to that register, or it is an `add' or `or' instruction + on that register. */ + +int +print_insn_sparc (bfd_vma memaddr, disassemble_info *info) +{ + FILE *stream = info->stream; + bfd_byte buffer[4]; + unsigned long insn; + sparc_opcode_hash *op; + /* Nonzero of opcode table has been initialized. */ + static int opcodes_initialized = 0; + /* bfd mach number of last call. */ + static unsigned long current_mach = 0; + bfd_vma (*getword) (const unsigned char *); + + if (!opcodes_initialized + || info->mach != current_mach) + { + int i; + + current_arch_mask = compute_arch_mask (info->mach); + + if (!opcodes_initialized) + sorted_opcodes = + malloc (sparc_num_opcodes * sizeof (sparc_opcode *)); + /* Reset the sorted table so we can resort it. */ + for (i = 0; i < sparc_num_opcodes; ++i) + sorted_opcodes[i] = &sparc_opcodes[i]; + qsort ((char *) sorted_opcodes, sparc_num_opcodes, + sizeof (sorted_opcodes[0]), compare_opcodes); + + build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); + current_mach = info->mach; + opcodes_initialized = 1; + } + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + /* On SPARClite variants such as DANlite (sparc86x), instructions + are always big-endian even when the machine is in little-endian mode. */ + if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) + getword = bfd_getb32; + else + getword = bfd_getl32; + + insn = getword (buffer); + + info->insn_info_valid = 1; /* We do return this info. */ + info->insn_type = dis_nonbranch; /* Assume non branch insn. */ + info->branch_delay_insns = 0; /* Assume no delay. */ + info->target = 0; /* Assume no target known. */ + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const sparc_opcode *opcode = op->opcode; + + /* If the insn isn't supported by the current architecture, skip it. */ + if (! (opcode->architecture & current_arch_mask)) + continue; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + int imm_ored_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Nonzero means we have an annulled branch. */ + /* int is_annulled = 0; */ /* see FIXME below */ + + /* Do we have an `add' or `or' instruction combining an + immediate with rs1? */ + if (opcode->match == 0x80102000) /* or */ + imm_ored_to_rs1 = 1; + if (opcode->match == 0x80002000) /* add */ + imm_added_to_rs1 = 1; + + if (X_RS1 (insn) != X_RD (insn) + && strchr (opcode->args, 'r') != NULL) + /* Can't do simple format if source and dest are different. */ + continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != NULL) + /* Can't do simple format if source and dest are different. */ + continue; + + (*info->fprintf_func) (stream, opcode->name); + + { + const char *s; + + if (opcode->args[0] != ',') + (*info->fprintf_func) (stream, " "); + + for (s = opcode->args; *s != '\0'; ++s) + { + while (*s == ',') + { + (*info->fprintf_func) (stream, ","); + ++s; + switch (*s) + { + case 'a': + (*info->fprintf_func) (stream, "a"); + /* is_annulled = 1; */ /* see FIXME below */ + ++s; + continue; + case 'N': + (*info->fprintf_func) (stream, "pn"); + ++s; + continue; + + case 'T': + (*info->fprintf_func) (stream, "pt"); + ++s; + continue; + + default: + break; + } + } + + (*info->fprintf_func) (stream, " "); + + switch (*s) + { + case '+': + found_plus = 1; + /* Fall through. */ + + default: + (*info->fprintf_func) (stream, "%c", *s); + break; + + case '#': + (*info->fprintf_func) (stream, "0"); + break; + +#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (X_RS1 (insn)); + break; + + case '2': + case 'O': + reg (X_RS2 (insn)); + break; + + case 'd': + reg (X_RD (insn)); + break; +#undef reg + +#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) +#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) + case 'e': + freg (X_RS1 (insn)); + break; + case 'v': /* Double/even. */ + case 'V': /* Quad/multiple of 4. */ + fregx (X_RS1 (insn)); + break; + + case 'f': + freg (X_RS2 (insn)); + break; + case 'B': /* Double/even. */ + case 'R': /* Quad/multiple of 4. */ + fregx (X_RS2 (insn)); + break; + + case 'g': + freg (X_RD (insn)); + break; + case 'H': /* Double/even. */ + case 'J': /* Quad/multiple of 4. */ + fregx (X_RD (insn)); + break; +#undef freg +#undef fregx + +#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (X_RS1 (insn)); + break; + + case 'c': + creg (X_RS2 (insn)); + break; + + case 'D': + creg (X_RD (insn)); + break; +#undef creg + + case 'h': + (*info->fprintf_func) (stream, "%%hi(%#x)", + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (insn) << 10))); + break; + + case 'i': /* 13 bit immediate. */ + case 'I': /* 11 bit immediate. */ + case 'j': /* 10 bit immediate. */ + { + int imm; + + if (*s == 'i') + imm = X_SIMM (insn, 13); + else if (*s == 'I') + imm = X_SIMM (insn, 11); + else + imm = X_SIMM (insn, 10); + + /* Check to see whether we have a 1+i, and take + note of that fact. + + Note: because of the way we sort the table, + we will be matching 1+i rather than i+1, + so it is OK to assume that i is after +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + (*info->fprintf_func) (stream, "%d", imm); + else + (*info->fprintf_func) (stream, "%#x", imm); + } + break; + + case 'X': /* 5 bit unsigned immediate. */ + case 'Y': /* 6 bit unsigned immediate. */ + { + int imm = X_IMM (insn, *s == 'X' ? 5 : 6); + + if (imm <= 9) + (info->fprintf_func) (stream, "%d", imm); + else + (info->fprintf_func) (stream, "%#x", (unsigned) imm); + } + break; + + case '3': + (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3)); + break; + + case 'K': + { + int mask = X_MEMBAR (insn); + int bit = 0x40, printed_one = 0; + const char *name; + + if (mask == 0) + (info->fprintf_func) (stream, "0"); + else + while (bit) + { + if (mask & bit) + { + if (printed_one) + (info->fprintf_func) (stream, "|"); + name = sparc_decode_membar (bit); + (info->fprintf_func) (stream, "%s", name); + printed_one = 1; + } + bit >>= 1; + } + break; + } + + case 'k': + info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'G': + info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; + (*info->print_address_func) (info->target, info); + break; + + case '6': + case '7': + case '8': + case '9': + (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); + break; + + case 'z': + (*info->fprintf_func) (stream, "%%icc"); + break; + + case 'Z': + (*info->fprintf_func) (stream, "%%xcc"); + break; + + case 'E': + (*info->fprintf_func) (stream, "%%ccr"); + break; + + case 's': + (*info->fprintf_func) (stream, "%%fprs"); + break; + + case 'o': + (*info->fprintf_func) (stream, "%%asi"); + break; + + case 'W': + (*info->fprintf_func) (stream, "%%tick"); + break; + + case 'P': + (*info->fprintf_func) (stream, "%%pc"); + break; + + case '?': + if (X_RS1 (insn) == 31) + (*info->fprintf_func) (stream, "%%ver"); + else if ((unsigned) X_RS1 (insn) < 17) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '!': + if ((unsigned) X_RD (insn) < 17) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '$': + if ((unsigned) X_RS1 (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '%': + if ((unsigned) X_RD (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '/': + if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RS1 (insn)-16]); + break; + + case '_': + if (X_RD (insn) < 16 || X_RD (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RD (insn)-16]); + break; + + case '*': + { + const char *name = sparc_decode_prefetch (X_RD (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%ld", X_RD (insn)); + break; + } + + case 'M': + (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn)); + break; + + case 'm': + (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn)); + break; + + case 'L': + info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'n': + (*info->fprintf_func) + (stream, "%#x", SEX (X_DISP22 (insn), 22)); + break; + + case 'l': + info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'A': + { + const char *name; + + if ((info->mach == bfd_mach_sparc_v8plusa) || + ((info->mach >= bfd_mach_sparc_v9) && + (info->mach <= bfd_mach_sparc_v9b))) + name = sparc_decode_asi_v9 (X_ASI (insn)); + else + name = sparc_decode_asi_v8 (X_ASI (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn)); + break; + } + + case 'C': + (*info->fprintf_func) (stream, "%%csr"); + break; + + case 'F': + (*info->fprintf_func) (stream, "%%fsr"); + break; + + case 'p': + (*info->fprintf_func) (stream, "%%psr"); + break; + + case 'q': + (*info->fprintf_func) (stream, "%%fq"); + break; + + case 'Q': + (*info->fprintf_func) (stream, "%%cq"); + break; + + case 't': + (*info->fprintf_func) (stream, "%%tbr"); + break; + + case 'w': + (*info->fprintf_func) (stream, "%%wim"); + break; + + case 'x': + (*info->fprintf_func) (stream, "%ld", + ((X_LDST_I (insn) << 8) + + X_ASI (insn))); + break; + + case 'y': + (*info->fprintf_func) (stream, "%%y"); + break; + + case 'u': + case 'U': + { + int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); + const char *name = sparc_decode_sparclet_cpreg (val); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%%cpreg(%d)", val); + break; + } + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_ored_to_rs1 || imm_added_to_rs1) + { + unsigned long prev_insn; + int errcode; + + if (memaddr >= 4) + errcode = + (*info->read_memory_func) + (memaddr - 4, buffer, sizeof (buffer), info); + else + errcode = 1; + + prev_insn = getword (buffer); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as: + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 */ + + if (is_delayed_branch (prev_insn)) + { + if (memaddr >= 8) + errcode = (*info->read_memory_func) + (memaddr - 8, buffer, sizeof (buffer), info); + else + errcode = 1; + + prev_insn = getword (buffer); + } + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn & 0xc1c00000) == 0x01000000 + && X_RD (prev_insn) == X_RS1 (insn)) + { + (*info->fprintf_func) (stream, "\t! "); + info->target = + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (prev_insn) << 10)); + if (imm_added_to_rs1) + info->target += X_SIMM (insn, 13); + else + info->target |= X_SIMM (insn, 13); + (*info->print_address_func) (info->target, info); + info->insn_type = dis_dref; + info->data_size = 4; /* FIXME!!! */ + } + } + } + + if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) + { + /* FIXME -- check is_annulled flag. */ + if (opcode->flags & F_UNBR) + info->insn_type = dis_branch; + if (opcode->flags & F_CONDBR) + info->insn_type = dis_condbranch; + if (opcode->flags & F_JSR) + info->insn_type = dis_jsr; + if (opcode->flags & F_DELAYED) + info->branch_delay_insns = 1; + } + + return sizeof (buffer); + } + } + + info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */ + (*info->fprintf_func) (stream, _("unknown")); + return sizeof (buffer); +} diff --git a/qemu/qemu-git/.svn/text-base/sparc.ld.svn-base b/qemu/qemu-git/.svn/text-base/sparc.ld.svn-base new file mode 100644 index 0000000..31321be --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/sparc.ld.svn-base @@ -0,0 +1,150 @@ +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", + "elf32-sparc") +OUTPUT_ARCH(sparc) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) } +} diff --git a/qemu/qemu-git/.svn/text-base/sparc64.ld.svn-base b/qemu/qemu-git/.svn/text-base/sparc64.ld.svn-base new file mode 100644 index 0000000..9ea4143 --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/sparc64.ld.svn-base @@ -0,0 +1,138 @@ +OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", + "elf64-sparc") +OUTPUT_ARCH(sparc:v9) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.gen_code) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/.svn/text-base/targphys.h.svn-base b/qemu/qemu-git/.svn/text-base/targphys.h.svn-base new file mode 100644 index 0000000..99ab23c --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/targphys.h.svn-base @@ -0,0 +1,24 @@ +/* Define target_phys_addr_t if it exists. */ + +#ifndef TARGPHYS_H +#define TARGPHYS_H + +#ifdef TARGET_PHYS_ADDR_BITS +/* target_phys_addr_t is the type of a physical address (its size can + be different from 'target_ulong'). We have sizeof(target_phys_addr) + = max(sizeof(unsigned long), + sizeof(size_of_target_physical_address)) because we must pass a + host pointer to memory operations in some cases */ + +#if TARGET_PHYS_ADDR_BITS == 32 +typedef uint32_t target_phys_addr_t; +#define TARGET_PHYS_ADDR_MAX UINT32_MAX +#define TARGET_FMT_plx "%08x" +#elif TARGET_PHYS_ADDR_BITS == 64 +typedef uint64_t target_phys_addr_t; +#define TARGET_PHYS_ADDR_MAX UINT64_MAX +#define TARGET_FMT_plx "%016" PRIx64 +#endif +#endif + +#endif diff --git a/qemu/qemu-git/.svn/text-base/tcg-runtime.c.svn-base b/qemu/qemu-git/.svn/text-base/tcg-runtime.c.svn-base new file mode 100644 index 0000000..219cade --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/tcg-runtime.c.svn-base @@ -0,0 +1,61 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "tcg/tcg-runtime.h" + +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2) +{ + return arg1 << arg2; +} + +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2) +{ + return (uint64_t)arg1 >> arg2; +} + +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2) +{ + return arg1 >> arg2; +} + +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2) +{ + return arg1 / arg2; +} + +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2) +{ + return arg1 % arg2; +} + +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 / arg2; +} + +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 % arg2; +} diff --git a/qemu/qemu-git/.svn/text-base/translate-all.c.svn-base b/qemu/qemu-git/.svn/text-base/translate-all.c.svn-base new file mode 100644 index 0000000..8ef8a0b --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/translate-all.c.svn-base @@ -0,0 +1,194 @@ +/* + * Host code generation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include +#include +#include +#include +#include + +#include "config.h" + +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg.h" + +/* code generation context */ +TCGContext tcg_ctx; + +uint16_t gen_opc_buf[OPC_BUF_SIZE]; +TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; + +target_ulong gen_opc_pc[OPC_BUF_SIZE]; +uint16_t gen_opc_icount[OPC_BUF_SIZE]; +uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +#if defined(TARGET_I386) +uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +#elif defined(TARGET_SPARC) +target_ulong gen_opc_npc[OPC_BUF_SIZE]; +target_ulong gen_opc_jump_pc[2]; +#elif defined(TARGET_MIPS) || defined(TARGET_SH4) +uint32_t gen_opc_hflags[OPC_BUF_SIZE]; +#endif + +/* XXX: suppress that */ +unsigned long code_gen_max_block_size(void) +{ + static unsigned long max; + + if (max == 0) { + max = TCG_MAX_OP_SIZE; +#define DEF(s, n, copy_size) max = copy_size > max? copy_size : max; +#include "tcg-opc.h" +#undef DEF + max *= OPC_MAX_SIZE; + } + + return max; +} + +void cpu_gen_init(void) +{ + tcg_context_init(&tcg_ctx); + tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); +} + +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ +int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) +{ + TCGContext *s = &tcg_ctx; + uint8_t *gen_code_buf; + int gen_code_size; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + +#ifdef CONFIG_PROFILER + s->tb_count1++; /* includes aborted translations because of + exceptions */ + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code(env, tb); + + /* generate machine code */ + gen_code_buf = tb->tc_ptr; + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + s->tb_next_offset = tb->tb_next_offset; +#ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; + /* the following two entries are optional (only used for string ops) */ + /* XXX: not used ? */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; +#else + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; +#endif + +#ifdef CONFIG_PROFILER + s->tb_count++; + s->interm_time += profile_getclock() - ti; + s->code_time -= profile_getclock(); +#endif + gen_code_size = tcg_gen_code(s, gen_code_buf); + *gen_code_size_ptr = gen_code_size; +#ifdef CONFIG_PROFILER + s->code_time += profile_getclock(); + s->code_in_len += tb->size; + s->code_out_len += gen_code_size; +#endif + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { + qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr); + log_disas(tb->tc_ptr, *gen_code_size_ptr); + qemu_log("\n"); + qemu_log_flush(); + } +#endif + return 0; +} + +/* The cpu state corresponding to 'searched_pc' is restored. + */ +int cpu_restore_state(TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc) +{ + TCGContext *s = &tcg_ctx; + int j; + unsigned long tc_ptr; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code_pc(env, tb); + + if (use_icount) { + /* Reset the cycle counter to the start of the block. */ + env->icount_decr.u16.low += tb->icount; + /* Clear the IO flag. */ + env->can_do_io = 0; + } + + /* find opc index corresponding to search_pc */ + tc_ptr = (unsigned long)tb->tc_ptr; + if (searched_pc < tc_ptr) + return -1; + + s->tb_next_offset = tb->tb_next_offset; +#ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; +#else + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; +#endif + j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr); + if (j < 0) + return -1; + /* now find start of instruction before */ + while (gen_opc_instr_start[j] == 0) + j--; + env->icount_decr.u16.low -= gen_opc_icount[j]; + + gen_pc_load(env, tb, searched_pc, j, puc); + +#ifdef CONFIG_PROFILER + s->restore_time += profile_getclock() - ti; + s->restore_count++; +#endif + return 0; +} diff --git a/qemu/qemu-git/.svn/text-base/x86_64.ld.svn-base b/qemu/qemu-git/.svn/text-base/x86_64.ld.svn-base new file mode 100644 index 0000000..24ea77d --- /dev/null +++ b/qemu/qemu-git/.svn/text-base/x86_64.ld.svn-base @@ -0,0 +1,170 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/qemu/qemu-git/Makefile-small b/qemu/qemu-git/Makefile-small new file mode 100644 index 0000000..a7e1dae --- /dev/null +++ b/qemu/qemu-git/Makefile-small @@ -0,0 +1,116 @@ +# -*- Mode: makefile -*- +# Makefile for QEMU. + +GENERATED_HEADERS = config-host.h + +ifneq ($(wildcard config-host.mak),) +# Put the all: rule here so that config-host.mak can contain dependencies. +all: build-all +include config-host.mak +include $(SRC_PATH)/rules.mak +config-host.mak: $(SRC_PATH)/configure-small + @echo $@ is out-of-date, running configure + @sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh +else +config-host.mak: + @echo "Please call configure before running make!" + @exit 1 +endif + +# Don't try to regenerate Makefile or configure +# We don't generate any of them +Makefile-small: ; +configure-small: ; + +.PHONY: all clean cscope distclean tar build-all + +$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) + +LIBS+=-lz + +SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) + +config-all-devices.mak: arm-softmmu/config-devices.mak + $(call quiet-command,cat arm-softmmu/config-devices.mak | grep =y | sort -u > $@," GEN $@") + +arm-softmmu/config-devices.mak: default-configs/arm-softmmu-small.mak + $(call quiet-command,cat $< > $@.tmp, " GEN $@") + @if test -f $@; then \ + if cmp -s $@.old $@ || cmp -s $@ $@.tmp; then \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ + else \ + if test -f $@.old; then \ + echo "WARNING: $@ (user modified) out of date.";\ + else \ + echo "WARNING: $@ out of date.";\ + fi; \ + echo "Run \"make defconfig\" to regenerate."; \ + rm $@.tmp; \ + fi; \ + else \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ + fi + +defconfig: + rm -f config-all-devices.mak arm-softmmu/config-devices.mak + +-include config-all-devices.mak + +build-all: subdir-arm-softmmu + +config-host.h: config-host.h-timestamp +config-host.h-timestamp: config-host.mak + +SUBDIR_RULES=subdir-arm-softmmu + +subdir-%: $(GENERATED_HEADERS) + $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) + +ifneq ($(wildcard config-host.mak),) +include $(SRC_PATH)/Makefile-small.objs +endif + +$(common-obj-y): $(GENERATED_HEADERS) +subdir-arm-softmmu: $(common-obj-y) + +###################################################################### + +$(block-obj-y): $(GENERATED_HEADERS) + +clean: + rm -f *.o *.d *.a TAGS cscope.* *~ */*~ + rm -f block/*.o block/*.d + for d in arm-softmmu libhw32 libhw64; do \ + if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ + done + +distclean: clean + rm -f config-host.mak config-host.h* config-host.ld + rm -f config-all-devices.mak + for d in arm-softmmu libhw32 libhw64; do \ + rm -rf $$d || exit 1 ; \ + done + +.PHONY: TAGS +TAGS: + find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags + +cscope: + rm -f ./cscope.* + find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files + cscope -b + +VERSION ?= $(shell cat VERSION) +FILE = qemu-$(VERSION) + +# tar release (use 'make -k tar' on a checkouted tree) +tar: + rm -rf /tmp/$(FILE) + cp -r . /tmp/$(FILE) + cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn + rm -rf /tmp/$(FILE) + +# Include automatically generated dependency files +-include $(wildcard *.d block/*.d) diff --git a/qemu/qemu-git/Makefile-small.hw b/qemu/qemu-git/Makefile-small.hw new file mode 100644 index 0000000..4a398cf --- /dev/null +++ b/qemu/qemu-git/Makefile-small.hw @@ -0,0 +1,25 @@ +# -*- Mode: makefile -*- +# Makefile for qemu target independent devices. + +include ../config-host.mak +include ../config-all-devices.mak +include config.mak +include $(SRC_PATH)/rules.mak + +.PHONY: all + +$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) + +QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu + +include $(SRC_PATH)/Makefile-small.objs + +all: $(hw-obj-y) +# Dummy command so that make thinks it has done something + @true + +clean: + rm -f *.o *.d *.a *~ + +# Include automatically generated dependency files +-include $(wildcard *.d */*.d) diff --git a/qemu/qemu-git/Makefile-small.objs b/qemu/qemu-git/Makefile-small.objs new file mode 100644 index 0000000..a2648a6 --- /dev/null +++ b/qemu/qemu-git/Makefile-small.objs @@ -0,0 +1,32 @@ +# -*- Mode: makefile -*- + +####################################################################### +# block-obj-y is code used by both qemu system emulation and qemu-img + +block-obj-y = cache-utils.o module.o +block-obj-y += block.o aio.o aes.o osdep.o +block-obj-$(CONFIG_POSIX) += posix-aio-compat.o +block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o + +block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o +block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o +block-nested-y += parallels.o +block-nested-$(CONFIG_WIN32) += raw-win32.o +block-nested-$(CONFIG_POSIX) += raw-posix.o +block-nested-$(CONFIG_CURL) += curl.o + +block-obj-y += $(addprefix block/, $(block-nested-y)) + +###################################################################### +# libqemu_common.a: Target independent part of system emulation. The +# long term path is to suppress *all* target specific code in case of +# system emulation, i.e. a single QEMU executable should support all +# CPUs and machines. + +common-obj-y = cutils.o qemu-malloc.o + +#common-obj-y += $(block-obj-y) + +common-obj-y += tcg-runtime.o host-utils.o + +common-obj-$(CONFIG_COCOA) += cocoa.o diff --git a/qemu/qemu-git/Makefile-small.target b/qemu/qemu-git/Makefile-small.target new file mode 100644 index 0000000..fe265d4 --- /dev/null +++ b/qemu/qemu-git/Makefile-small.target @@ -0,0 +1,104 @@ +# -*- Mode: makefile -*- + +GENERATED_HEADERS = config-target.h + +include ../config-host.mak +include config-devices.mak +include config-target.mak +include $(SRC_PATH)/rules.mak +ifneq ($(HWDIR),) +include $(HWDIR)/config.mak +endif + +TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) +$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw) +QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H + +include $(SRC_PATH)/Makefile-small.objs + +# system emulator name +QEMU_PROG=qemu-system-arm$(EXESUF) + +PROGS=$(QEMU_PROG) + +LIBS+=-lm + +config-target.h: config-target.h-timestamp +config-target.h-timestamp: config-target.mak + +all: $(PROGS) + +# Dummy command so that make thinks it has done something + @true + +######################################################### +# cpu emulator library +libobj-y = exec.o translate-all.o cpu-exec.o translate.o +libobj-y += tcg/tcg.o +libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o +libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o +libobj-y += op_helper.o helper.o +libobj-$(CONFIG_NEED_MMU) += mmu.o +libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o + +# NOTE: the disassembler code is only needed for debugging +libobj-y += disas.o +libobj-$(CONFIG_ALPHA_DIS) += alpha-dis.o +libobj-$(CONFIG_ARM_DIS) += arm-dis.o +libobj-$(CONFIG_CRIS_DIS) += cris-dis.o +libobj-$(CONFIG_HPPA_DIS) += hppa-dis.o +libobj-$(CONFIG_I386_DIS) += i386-dis.o +libobj-$(CONFIG_M68K_DIS) += m68k-dis.o +libobj-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o +libobj-$(CONFIG_MIPS_DIS) += mips-dis.o +libobj-$(CONFIG_PPC_DIS) += ppc-dis.o +libobj-$(CONFIG_S390_DIS) += s390-dis.o +libobj-$(CONFIG_SH4_DIS) += sh4-dis.o +libobj-$(CONFIG_SPARC_DIS) += sparc-dis.o + +$(libobj-y): $(GENERATED_HEADERS) + +# libqemu + +translate.o: translate.c cpu.h + +translate-all.o: translate-all.c cpu.h + +tcg/tcg.o: cpu.h + +# HELPER_CFLAGS is used for all the code compiled with static register +# variables +op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + +######################################################### +# System emulator target +ifdef CONFIG_SOFTMMU + +#obj-y = gdbstub.o +LIBS+=-lz + +main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) + +$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) + +obj-y += $(addprefix ../, $(common-obj-y)) +obj-y += $(libobj-y) + +endif # CONFIG_SOFTMMU + +#obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o + +$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) +# $(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)) + + +gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh + $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") + +clean: + rm -f *.o *.a *~ $(PROGS) fpu/*.o + rm -f *.d */*.d tcg/*.o + rm -f gdbstub-xml.c + +# Include automatically generated dependency files +-include $(wildcard *.d */*.d) diff --git a/qemu/qemu-git/VERSION b/qemu/qemu-git/VERSION new file mode 100644 index 0000000..d9e30b8 --- /dev/null +++ b/qemu/qemu-git/VERSION @@ -0,0 +1 @@ +0.12.50 diff --git a/qemu/qemu-git/alpha-dis.c b/qemu/qemu-git/alpha-dis.c new file mode 100644 index 0000000..970da5b --- /dev/null +++ b/qemu/qemu-git/alpha-dis.c @@ -0,0 +1,1917 @@ +/* alpha-dis.c -- Disassemble Alpha AXP instructions + Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Richard Henderson , + patterned after the PPC opcode handling written by Ian Lance Taylor. + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, see +. */ + +#include +#include "dis-asm.h" + +/* The opcode table is an array of struct alpha_opcode. */ + +struct alpha_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned mask; + + /* One bit flags for the opcode. These are primarily used to + indicate specific processors and environments support the + instructions. The defined values are listed below. */ + unsigned flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[4]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct alpha_opcode alpha_opcodes[]; +extern const unsigned alpha_num_opcodes; + +/* Values defined for the flags field of a struct alpha_opcode. */ + +/* CPU Availability */ +#define AXP_OPCODE_BASE 0x0001 /* Base architecture -- all cpus. */ +#define AXP_OPCODE_EV4 0x0002 /* EV4 specific PALcode insns. */ +#define AXP_OPCODE_EV5 0x0004 /* EV5 specific PALcode insns. */ +#define AXP_OPCODE_EV6 0x0008 /* EV6 specific PALcode insns. */ +#define AXP_OPCODE_BWX 0x0100 /* Byte/word extension (amask bit 0). */ +#define AXP_OPCODE_CIX 0x0200 /* "Count" extension (amask bit 1). */ +#define AXP_OPCODE_MAX 0x0400 /* Multimedia extension (amask bit 8). */ + +#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6)) + +/* A macro to extract the major opcode from an instruction. */ +#define AXP_OP(i) (((i) >> 26) & 0x3F) + +/* The total number of major opcodes. */ +#define AXP_NOPS 0x40 + + +/* The operands table is an array of struct alpha_operand. */ + +struct alpha_operand +{ + /* The number of bits in the operand. */ + unsigned int bits : 5; + + /* How far the operand is left shifted in the instruction. */ + unsigned int shift : 5; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* One bit syntax flags. */ + unsigned int flags : 16; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned (*insert) (unsigned instruction, int op, + const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & AXP_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + int (*extract) (unsigned instruction, int *invalid); +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the alpha_opcodes table. */ + +extern const struct alpha_operand alpha_operands[]; +extern const unsigned alpha_num_operands; + +/* Values defined for the flags field of a struct alpha_operand. */ + +/* Mask for selecting the type for typecheck purposes */ +#define AXP_OPERAND_TYPECHECK_MASK \ + (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \ + AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \ + AXP_OPERAND_UNSIGNED) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics, for which two operands fields + are identical. The assembler should call the insert function with + any op value. The disassembler should call the extract function, + ignore the return value, and check the value placed in the invalid + argument. */ +#define AXP_OPERAND_FAKE 01 + +/* The operand should be wrapped in parentheses rather than separated + from the previous by a comma. This is used for the load and store + instructions which want their operands to look like "Ra,disp(Rb)". */ +#define AXP_OPERAND_PARENS 02 + +/* Used in combination with PARENS, this suppresses the suppression of + the comma. This is used for "jmp Ra,(Rb),hint". */ +#define AXP_OPERAND_COMMA 04 + +/* This operand names an integer register. */ +#define AXP_OPERAND_IR 010 + +/* This operand names a floating point register. */ +#define AXP_OPERAND_FPR 020 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define AXP_OPERAND_RELATIVE 040 + +/* This operand takes signed values. */ +#define AXP_OPERAND_SIGNED 0100 + +/* This operand takes unsigned values. This exists primarily so that + a flags value of 0 can be treated as end-of-arguments. */ +#define AXP_OPERAND_UNSIGNED 0200 + +/* Suppress overflow detection on this field. This is used for hints. */ +#define AXP_OPERAND_NOOVERFLOW 0400 + +/* Mask for optional argument default value. */ +#define AXP_OPERAND_OPTIONAL_MASK 07000 + +/* This operand defaults to zero. This is used for jump hints. */ +#define AXP_OPERAND_DEFAULT_ZERO 01000 + +/* This operand should default to the first (real) operand and is used + in conjunction with AXP_OPERAND_OPTIONAL. This allows + "and $0,3,$0" to be written as "and $0,3", etc. I don't like + it, but it's what DEC does. */ +#define AXP_OPERAND_DEFAULT_FIRST 02000 + +/* Similarly, this operand should default to the second (real) operand. + This allows "negl $0" instead of "negl $0,$0". */ +#define AXP_OPERAND_DEFAULT_SECOND 04000 + + +/* Register common names */ + +#define AXP_REG_V0 0 +#define AXP_REG_T0 1 +#define AXP_REG_T1 2 +#define AXP_REG_T2 3 +#define AXP_REG_T3 4 +#define AXP_REG_T4 5 +#define AXP_REG_T5 6 +#define AXP_REG_T6 7 +#define AXP_REG_T7 8 +#define AXP_REG_S0 9 +#define AXP_REG_S1 10 +#define AXP_REG_S2 11 +#define AXP_REG_S3 12 +#define AXP_REG_S4 13 +#define AXP_REG_S5 14 +#define AXP_REG_FP 15 +#define AXP_REG_A0 16 +#define AXP_REG_A1 17 +#define AXP_REG_A2 18 +#define AXP_REG_A3 19 +#define AXP_REG_A4 20 +#define AXP_REG_A5 21 +#define AXP_REG_T8 22 +#define AXP_REG_T9 23 +#define AXP_REG_T10 24 +#define AXP_REG_T11 25 +#define AXP_REG_RA 26 +#define AXP_REG_PV 27 +#define AXP_REG_T12 27 +#define AXP_REG_AT 28 +#define AXP_REG_GP 29 +#define AXP_REG_SP 30 +#define AXP_REG_ZERO 31 + +#define bfd_mach_alpha_ev4 0x10 +#define bfd_mach_alpha_ev5 0x20 +#define bfd_mach_alpha_ev6 0x30 + +enum bfd_reloc_code_real { + BFD_RELOC_23_PCREL_S2, + BFD_RELOC_ALPHA_HINT +}; + +/* This file holds the Alpha AXP opcode table. The opcode table includes + almost all of the extended instruction mnemonics. This permits the + disassembler to use them, and simplifies the assembler logic, at the + cost of increasing the table size. The table is strictly constant + data, so the compiler should be able to put it in the text segment. + + This file also holds the operand table. All knowledge about inserting + and extracting operands from instructions is kept in this file. + + The information for the base instruction set was compiled from the + _Alpha Architecture Handbook_, Digital Order Number EC-QD2KB-TE, + version 2. + + The information for the post-ev5 architecture extensions BWX, CIX and + MAX came from version 3 of this same document, which is also available + on-line at http://ftp.digital.com/pub/Digital/info/semiconductor + /literature/alphahb2.pdf + + The information for the EV4 PALcode instructions was compiled from + _DECchip 21064 and DECchip 21064A Alpha AXP Microprocessors Hardware + Reference Manual_, Digital Order Number EC-Q9ZUA-TE, preliminary + revision dated June 1994. + + The information for the EV5 PALcode instructions was compiled from + _Alpha 21164 Microprocessor Hardware Reference Manual_, Digital + Order Number EC-QAEQB-TE, preliminary revision dated April 1995. */ + +/* Local insertion and extraction functions */ + +static unsigned insert_rba (unsigned, int, const char **); +static unsigned insert_rca (unsigned, int, const char **); +static unsigned insert_za (unsigned, int, const char **); +static unsigned insert_zb (unsigned, int, const char **); +static unsigned insert_zc (unsigned, int, const char **); +static unsigned insert_bdisp (unsigned, int, const char **); +static unsigned insert_jhint (unsigned, int, const char **); +static unsigned insert_ev6hwjhint (unsigned, int, const char **); + +static int extract_rba (unsigned, int *); +static int extract_rca (unsigned, int *); +static int extract_za (unsigned, int *); +static int extract_zb (unsigned, int *); +static int extract_zc (unsigned, int *); +static int extract_bdisp (unsigned, int *); +static int extract_jhint (unsigned, int *); +static int extract_ev6hwjhint (unsigned, int *); + + +/* The operands table */ + +const struct alpha_operand alpha_operands[] = +{ + /* The fields are bits, shift, insert, extract, flags */ + /* The zero index is used to indicate end-of-list */ +#define UNUSED 0 + { 0, 0, 0, 0, 0, 0 }, + + /* The plain integer register fields */ +#define RA (UNUSED + 1) + { 5, 21, 0, AXP_OPERAND_IR, 0, 0 }, +#define RB (RA + 1) + { 5, 16, 0, AXP_OPERAND_IR, 0, 0 }, +#define RC (RB + 1) + { 5, 0, 0, AXP_OPERAND_IR, 0, 0 }, + + /* The plain fp register fields */ +#define FA (RC + 1) + { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FB (FA + 1) + { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FC (FB + 1) + { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 }, + + /* The integer registers when they are ZERO */ +#define ZA (FC + 1) + { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za }, +#define ZB (ZA + 1) + { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb }, +#define ZC (ZB + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc }, + + /* The RB field when it needs parentheses */ +#define PRB (ZC + 1) + { 5, 16, 0, AXP_OPERAND_IR|AXP_OPERAND_PARENS, 0, 0 }, + + /* The RB field when it needs parentheses _and_ a preceding comma */ +#define CPRB (PRB + 1) + { 5, 16, 0, + AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA, 0, 0 }, + + /* The RB field when it must be the same as the RA field */ +#define RBA (CPRB + 1) + { 5, 16, 0, AXP_OPERAND_FAKE, insert_rba, extract_rba }, + + /* The RC field when it must be the same as the RB field */ +#define RCA (RBA + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_rca, extract_rca }, + + /* The RC field when it can *default* to RA */ +#define DRC1 (RCA + 1) + { 5, 0, 0, + AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The RC field when it can *default* to RB */ +#define DRC2 (DRC1 + 1) + { 5, 0, 0, + AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The FC field when it can *default* to RA */ +#define DFC1 (DRC2 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The FC field when it can *default* to RB */ +#define DFC2 (DFC1 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The unsigned 8-bit literal of Operate format insns */ +#define LIT (DFC2 + 1) + { 8, 13, -LIT, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The signed 16-bit displacement of Memory format insns. From here + we can't tell what relocation should be used, so don't use a default. */ +#define MDISP (LIT + 1) + { 16, 0, -MDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The signed "23-bit" aligned displacement of Branch format insns */ +#define BDISP (MDISP + 1) + { 21, 0, BFD_RELOC_23_PCREL_S2, + AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, + + /* The 26-bit PALcode function */ +#define PALFN (BDISP + 1) + { 26, 0, -PALFN, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint */ +#define JMPHINT (PALFN + 1) + { 14, 0, BFD_RELOC_ALPHA_HINT, + AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW, + insert_jhint, extract_jhint }, + + /* The optional hint to RET/JSR_COROUTINE */ +#define RETHINT (JMPHINT + 1) + { 14, 0, -RETHINT, + AXP_OPERAND_UNSIGNED|AXP_OPERAND_DEFAULT_ZERO, 0, 0 }, + + /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns */ +#define EV4HWDISP (RETHINT + 1) +#define EV6HWDISP (EV4HWDISP) + { 12, 0, -EV4HWDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The 5-bit index for the ev4 hw_m[ft]pr (pal19/pal1d) insns */ +#define EV4HWINDEX (EV4HWDISP + 1) + { 5, 0, -EV4HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 8-bit index for the oddly unqualified hw_m[tf]pr insns + that occur in DEC PALcode. */ +#define EV4EXTHWINDEX (EV4HWINDEX + 1) + { 8, 0, -EV4EXTHWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 10-bit displacement for the ev5 hw_{ld,st} (pal1b/pal1f) insns */ +#define EV5HWDISP (EV4EXTHWINDEX + 1) + { 10, 0, -EV5HWDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The 16-bit index for the ev5 hw_m[ft]pr (pal19/pal1d) insns */ +#define EV5HWINDEX (EV5HWDISP + 1) + { 16, 0, -EV5HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 16-bit combined index/scoreboard mask for the ev6 + hw_m[ft]pr (pal19/pal1d) insns */ +#define EV6HWINDEX (EV5HWINDEX + 1) + { 16, 0, -EV6HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn */ +#define EV6HWJMPHINT (EV6HWINDEX+ 1) + { 8, 0, -EV6HWJMPHINT, + AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW, + insert_ev6hwjhint, extract_ev6hwjhint } +}; + +const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operands); + +/* The RB field when it is the same as the RA field in the same insn. + This operand is marked fake. The insertion function just copies + the RA field into the RB field, and the extraction function just + checks that the fields are the same. */ + +/*ARGSUSED*/ +static unsigned +insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static int +extract_rba(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + + +/* The same for the RC field */ + +/*ARGSUSED*/ +static unsigned +insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((insn >> 21) & 0x1f); +} + +static int +extract_rca(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != (insn & 0x1f)) + *invalid = 1; + return 0; +} + + +/* Fake arguments in which the registers must be set to ZERO */ + +/*ARGSUSED*/ +static unsigned +insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 21); +} + +static int +extract_za(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +/*ARGSUSED*/ +static unsigned +insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 16); +} + +static int +extract_zb(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +/*ARGSUSED*/ +static unsigned +insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | 31; +} + +static int +extract_zc(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && (insn & 0x1f) != 31) + *invalid = 1; + return 0; +} + + +/* The displacement field of a Branch format insn. */ + +static unsigned +insert_bdisp(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("branch operand unaligned"); + return insn | ((value / 4) & 0x1FFFFF); +} + +/*ARGSUSED*/ +static int +extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); +} + + +/* The hint field of a JMP/JSR insn. */ + +static unsigned +insert_jhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("jump hint unaligned"); + return insn | ((value / 4) & 0x3FFF); +} + +/*ARGSUSED*/ +static int +extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000); +} + +/* The hint field of an EV6 HW_JMP/JSR insn. */ + +static unsigned +insert_ev6hwjhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = _("jump hint unaligned"); + return insn | ((value / 4) & 0x1FFF); +} + +/*ARGSUSED*/ +static int +extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); +} + + +/* Macros used to form opcodes */ + +/* The main opcode */ +#define OP(x) (((x) & 0x3F) << 26) +#define OP_MASK 0xFC000000 + +/* Branch format instructions */ +#define BRA_(oo) OP(oo) +#define BRA_MASK OP_MASK +#define BRA(oo) BRA_(oo), BRA_MASK + +/* Floating point format instructions */ +#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5)) +#define FP_MASK (OP_MASK | 0xFFE0) +#define FP(oo,fff) FP_(oo,fff), FP_MASK + +/* Memory format instructions */ +#define MEM_(oo) OP(oo) +#define MEM_MASK OP_MASK +#define MEM(oo) MEM_(oo), MEM_MASK + +/* Memory/Func Code format instructions */ +#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF)) +#define MFC_MASK (OP_MASK | 0xFFFF) +#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK + +/* Memory/Branch format instructions */ +#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14)) +#define MBR_MASK (OP_MASK | 0xC000) +#define MBR(oo,h) MBR_(oo,h), MBR_MASK + +/* Operate format instructions. The OPRL variant specifies a + literal second argument. */ +#define OPR_(oo,ff) (OP(oo) | (((ff) & 0x7F) << 5)) +#define OPRL_(oo,ff) (OPR_((oo),(ff)) | 0x1000) +#define OPR_MASK (OP_MASK | 0x1FE0) +#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK +#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK + +/* Generic PALcode format instructions */ +#define PCD_(oo) OP(oo) +#define PCD_MASK OP_MASK +#define PCD(oo) PCD_(oo), PCD_MASK + +/* Specific PALcode instructions */ +#define SPCD_(oo,ffff) (OP(oo) | ((ffff) & 0x3FFFFFF)) +#define SPCD_MASK 0xFFFFFFFF +#define SPCD(oo,ffff) SPCD_(oo,ffff), SPCD_MASK + +/* Hardware memory (hw_{ld,st}) instructions */ +#define EV4HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) +#define EV4HWMEM_MASK (OP_MASK | 0xF000) +#define EV4HWMEM(oo,f) EV4HWMEM_(oo,f), EV4HWMEM_MASK + +#define EV5HWMEM_(oo,f) (OP(oo) | (((f) & 0x3F) << 10)) +#define EV5HWMEM_MASK (OP_MASK | 0xF800) +#define EV5HWMEM(oo,f) EV5HWMEM_(oo,f), EV5HWMEM_MASK + +#define EV6HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) +#define EV6HWMEM_MASK (OP_MASK | 0xF000) +#define EV6HWMEM(oo,f) EV6HWMEM_(oo,f), EV6HWMEM_MASK + +#define EV6HWMBR_(oo,h) (OP(oo) | (((h) & 7) << 13)) +#define EV6HWMBR_MASK (OP_MASK | 0xE000) +#define EV6HWMBR(oo,h) EV6HWMBR_(oo,h), EV6HWMBR_MASK + +/* Abbreviations for instruction subsets. */ +#define BASE AXP_OPCODE_BASE +#define EV4 AXP_OPCODE_EV4 +#define EV5 AXP_OPCODE_EV5 +#define EV6 AXP_OPCODE_EV6 +#define BWX AXP_OPCODE_BWX +#define CIX AXP_OPCODE_CIX +#define MAX AXP_OPCODE_MAX + +/* Common combinations of arguments */ +#define ARG_NONE { 0 } +#define ARG_BRA { RA, BDISP } +#define ARG_FBRA { FA, BDISP } +#define ARG_FP { FA, FB, DFC1 } +#define ARG_FPZ1 { ZA, FB, DFC1 } +#define ARG_MEM { RA, MDISP, PRB } +#define ARG_FMEM { FA, MDISP, PRB } +#define ARG_OPR { RA, RB, DRC1 } +#define ARG_OPRL { RA, LIT, DRC1 } +#define ARG_OPRZ1 { ZA, RB, DRC1 } +#define ARG_OPRLZ1 { ZA, LIT, RC } +#define ARG_PCD { PALFN } +#define ARG_EV4HWMEM { RA, EV4HWDISP, PRB } +#define ARG_EV4HWMPR { RA, RBA, EV4HWINDEX } +#define ARG_EV5HWMEM { RA, EV5HWDISP, PRB } +#define ARG_EV6HWMEM { RA, EV6HWDISP, PRB } + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK { OPERANDS } + + NAME is the name of the instruction. + + OPCODE is the instruction opcode. + + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + + OPERANDS is the list of operands. + + The preceding macros merge the text of the OPCODE and MASK fields. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. + + Otherwise, it is sorted by major opcode and minor function code. + + There are three classes of not-really-instructions in this table: + + ALIAS is another name for another instruction. Some of + these come from the Architecture Handbook, some + come from the original gas opcode tables. In all + cases, the functionality of the opcode is unchanged. + + PSEUDO a stylized code form endorsed by Chapter A.4 of the + Architecture Handbook. + + EXTRA a stylized code form found in the original gas tables. + + And two annotations: + + EV56 BUT opcodes that are officially introduced as of the ev56, + but with defined results on previous implementations. + + EV56 UNA opcodes that were introduced as of the ev56 with + presumably undefined results on previous implementations + that were not assigned to a particular extension. +*/ + +const struct alpha_opcode alpha_opcodes[] = { + { "halt", SPCD(0x00,0x0000), BASE, ARG_NONE }, + { "draina", SPCD(0x00,0x0002), BASE, ARG_NONE }, + { "bpt", SPCD(0x00,0x0080), BASE, ARG_NONE }, + { "bugchk", SPCD(0x00,0x0081), BASE, ARG_NONE }, + { "callsys", SPCD(0x00,0x0083), BASE, ARG_NONE }, + { "chmk", SPCD(0x00,0x0083), BASE, ARG_NONE }, + { "imb", SPCD(0x00,0x0086), BASE, ARG_NONE }, + { "rduniq", SPCD(0x00,0x009e), BASE, ARG_NONE }, + { "wruniq", SPCD(0x00,0x009f), BASE, ARG_NONE }, + { "gentrap", SPCD(0x00,0x00aa), BASE, ARG_NONE }, + { "call_pal", PCD(0x00), BASE, ARG_PCD }, + { "pal", PCD(0x00), BASE, ARG_PCD }, /* alias */ + + { "lda", MEM(0x08), BASE, { RA, MDISP, ZB } }, /* pseudo */ + { "lda", MEM(0x08), BASE, ARG_MEM }, + { "ldah", MEM(0x09), BASE, { RA, MDISP, ZB } }, /* pseudo */ + { "ldah", MEM(0x09), BASE, ARG_MEM }, + { "ldbu", MEM(0x0A), BWX, ARG_MEM }, + { "unop", MEM_(0x0B) | (30 << 16), + MEM_MASK, BASE, { ZA } }, /* pseudo */ + { "ldq_u", MEM(0x0B), BASE, ARG_MEM }, + { "ldwu", MEM(0x0C), BWX, ARG_MEM }, + { "stw", MEM(0x0D), BWX, ARG_MEM }, + { "stb", MEM(0x0E), BWX, ARG_MEM }, + { "stq_u", MEM(0x0F), BASE, ARG_MEM }, + + { "sextl", OPR(0x10,0x00), BASE, ARG_OPRZ1 }, /* pseudo */ + { "sextl", OPRL(0x10,0x00), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "addl", OPR(0x10,0x00), BASE, ARG_OPR }, + { "addl", OPRL(0x10,0x00), BASE, ARG_OPRL }, + { "s4addl", OPR(0x10,0x02), BASE, ARG_OPR }, + { "s4addl", OPRL(0x10,0x02), BASE, ARG_OPRL }, + { "negl", OPR(0x10,0x09), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negl", OPRL(0x10,0x09), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subl", OPR(0x10,0x09), BASE, ARG_OPR }, + { "subl", OPRL(0x10,0x09), BASE, ARG_OPRL }, + { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR }, + { "s4subl", OPRL(0x10,0x0B), BASE, ARG_OPRL }, + { "cmpbge", OPR(0x10,0x0F), BASE, ARG_OPR }, + { "cmpbge", OPRL(0x10,0x0F), BASE, ARG_OPRL }, + { "s8addl", OPR(0x10,0x12), BASE, ARG_OPR }, + { "s8addl", OPRL(0x10,0x12), BASE, ARG_OPRL }, + { "s8subl", OPR(0x10,0x1B), BASE, ARG_OPR }, + { "s8subl", OPRL(0x10,0x1B), BASE, ARG_OPRL }, + { "cmpult", OPR(0x10,0x1D), BASE, ARG_OPR }, + { "cmpult", OPRL(0x10,0x1D), BASE, ARG_OPRL }, + { "addq", OPR(0x10,0x20), BASE, ARG_OPR }, + { "addq", OPRL(0x10,0x20), BASE, ARG_OPRL }, + { "s4addq", OPR(0x10,0x22), BASE, ARG_OPR }, + { "s4addq", OPRL(0x10,0x22), BASE, ARG_OPRL }, + { "negq", OPR(0x10,0x29), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negq", OPRL(0x10,0x29), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subq", OPR(0x10,0x29), BASE, ARG_OPR }, + { "subq", OPRL(0x10,0x29), BASE, ARG_OPRL }, + { "s4subq", OPR(0x10,0x2B), BASE, ARG_OPR }, + { "s4subq", OPRL(0x10,0x2B), BASE, ARG_OPRL }, + { "cmpeq", OPR(0x10,0x2D), BASE, ARG_OPR }, + { "cmpeq", OPRL(0x10,0x2D), BASE, ARG_OPRL }, + { "s8addq", OPR(0x10,0x32), BASE, ARG_OPR }, + { "s8addq", OPRL(0x10,0x32), BASE, ARG_OPRL }, + { "s8subq", OPR(0x10,0x3B), BASE, ARG_OPR }, + { "s8subq", OPRL(0x10,0x3B), BASE, ARG_OPRL }, + { "cmpule", OPR(0x10,0x3D), BASE, ARG_OPR }, + { "cmpule", OPRL(0x10,0x3D), BASE, ARG_OPRL }, + { "addl/v", OPR(0x10,0x40), BASE, ARG_OPR }, + { "addl/v", OPRL(0x10,0x40), BASE, ARG_OPRL }, + { "negl/v", OPR(0x10,0x49), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negl/v", OPRL(0x10,0x49), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subl/v", OPR(0x10,0x49), BASE, ARG_OPR }, + { "subl/v", OPRL(0x10,0x49), BASE, ARG_OPRL }, + { "cmplt", OPR(0x10,0x4D), BASE, ARG_OPR }, + { "cmplt", OPRL(0x10,0x4D), BASE, ARG_OPRL }, + { "addq/v", OPR(0x10,0x60), BASE, ARG_OPR }, + { "addq/v", OPRL(0x10,0x60), BASE, ARG_OPRL }, + { "negq/v", OPR(0x10,0x69), BASE, ARG_OPRZ1 }, /* pseudo */ + { "negq/v", OPRL(0x10,0x69), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "subq/v", OPR(0x10,0x69), BASE, ARG_OPR }, + { "subq/v", OPRL(0x10,0x69), BASE, ARG_OPRL }, + { "cmple", OPR(0x10,0x6D), BASE, ARG_OPR }, + { "cmple", OPRL(0x10,0x6D), BASE, ARG_OPRL }, + + { "and", OPR(0x11,0x00), BASE, ARG_OPR }, + { "and", OPRL(0x11,0x00), BASE, ARG_OPRL }, + { "andnot", OPR(0x11,0x08), BASE, ARG_OPR }, /* alias */ + { "andnot", OPRL(0x11,0x08), BASE, ARG_OPRL }, /* alias */ + { "bic", OPR(0x11,0x08), BASE, ARG_OPR }, + { "bic", OPRL(0x11,0x08), BASE, ARG_OPRL }, + { "cmovlbs", OPR(0x11,0x14), BASE, ARG_OPR }, + { "cmovlbs", OPRL(0x11,0x14), BASE, ARG_OPRL }, + { "cmovlbc", OPR(0x11,0x16), BASE, ARG_OPR }, + { "cmovlbc", OPRL(0x11,0x16), BASE, ARG_OPRL }, + { "nop", OPR(0x11,0x20), BASE, { ZA, ZB, ZC } }, /* pseudo */ + { "clr", OPR(0x11,0x20), BASE, { ZA, ZB, RC } }, /* pseudo */ + { "mov", OPR(0x11,0x20), BASE, { ZA, RB, RC } }, /* pseudo */ + { "mov", OPR(0x11,0x20), BASE, { RA, RBA, RC } }, /* pseudo */ + { "mov", OPRL(0x11,0x20), BASE, { ZA, LIT, RC } }, /* pseudo */ + { "or", OPR(0x11,0x20), BASE, ARG_OPR }, /* alias */ + { "or", OPRL(0x11,0x20), BASE, ARG_OPRL }, /* alias */ + { "bis", OPR(0x11,0x20), BASE, ARG_OPR }, + { "bis", OPRL(0x11,0x20), BASE, ARG_OPRL }, + { "cmoveq", OPR(0x11,0x24), BASE, ARG_OPR }, + { "cmoveq", OPRL(0x11,0x24), BASE, ARG_OPRL }, + { "cmovne", OPR(0x11,0x26), BASE, ARG_OPR }, + { "cmovne", OPRL(0x11,0x26), BASE, ARG_OPRL }, + { "not", OPR(0x11,0x28), BASE, ARG_OPRZ1 }, /* pseudo */ + { "not", OPRL(0x11,0x28), BASE, ARG_OPRLZ1 }, /* pseudo */ + { "ornot", OPR(0x11,0x28), BASE, ARG_OPR }, + { "ornot", OPRL(0x11,0x28), BASE, ARG_OPRL }, + { "xor", OPR(0x11,0x40), BASE, ARG_OPR }, + { "xor", OPRL(0x11,0x40), BASE, ARG_OPRL }, + { "cmovlt", OPR(0x11,0x44), BASE, ARG_OPR }, + { "cmovlt", OPRL(0x11,0x44), BASE, ARG_OPRL }, + { "cmovge", OPR(0x11,0x46), BASE, ARG_OPR }, + { "cmovge", OPRL(0x11,0x46), BASE, ARG_OPRL }, + { "eqv", OPR(0x11,0x48), BASE, ARG_OPR }, + { "eqv", OPRL(0x11,0x48), BASE, ARG_OPRL }, + { "xornot", OPR(0x11,0x48), BASE, ARG_OPR }, /* alias */ + { "xornot", OPRL(0x11,0x48), BASE, ARG_OPRL }, /* alias */ + { "amask", OPR(0x11,0x61), BASE, ARG_OPRZ1 }, /* ev56 but */ + { "amask", OPRL(0x11,0x61), BASE, ARG_OPRLZ1 }, /* ev56 but */ + { "cmovle", OPR(0x11,0x64), BASE, ARG_OPR }, + { "cmovle", OPRL(0x11,0x64), BASE, ARG_OPRL }, + { "cmovgt", OPR(0x11,0x66), BASE, ARG_OPR }, + { "cmovgt", OPRL(0x11,0x66), BASE, ARG_OPRL }, + { "implver", OPRL_(0x11,0x6C)|(31<<21)|(1<<13), + 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */ + + { "mskbl", OPR(0x12,0x02), BASE, ARG_OPR }, + { "mskbl", OPRL(0x12,0x02), BASE, ARG_OPRL }, + { "extbl", OPR(0x12,0x06), BASE, ARG_OPR }, + { "extbl", OPRL(0x12,0x06), BASE, ARG_OPRL }, + { "insbl", OPR(0x12,0x0B), BASE, ARG_OPR }, + { "insbl", OPRL(0x12,0x0B), BASE, ARG_OPRL }, + { "mskwl", OPR(0x12,0x12), BASE, ARG_OPR }, + { "mskwl", OPRL(0x12,0x12), BASE, ARG_OPRL }, + { "extwl", OPR(0x12,0x16), BASE, ARG_OPR }, + { "extwl", OPRL(0x12,0x16), BASE, ARG_OPRL }, + { "inswl", OPR(0x12,0x1B), BASE, ARG_OPR }, + { "inswl", OPRL(0x12,0x1B), BASE, ARG_OPRL }, + { "mskll", OPR(0x12,0x22), BASE, ARG_OPR }, + { "mskll", OPRL(0x12,0x22), BASE, ARG_OPRL }, + { "extll", OPR(0x12,0x26), BASE, ARG_OPR }, + { "extll", OPRL(0x12,0x26), BASE, ARG_OPRL }, + { "insll", OPR(0x12,0x2B), BASE, ARG_OPR }, + { "insll", OPRL(0x12,0x2B), BASE, ARG_OPRL }, + { "zap", OPR(0x12,0x30), BASE, ARG_OPR }, + { "zap", OPRL(0x12,0x30), BASE, ARG_OPRL }, + { "zapnot", OPR(0x12,0x31), BASE, ARG_OPR }, + { "zapnot", OPRL(0x12,0x31), BASE, ARG_OPRL }, + { "mskql", OPR(0x12,0x32), BASE, ARG_OPR }, + { "mskql", OPRL(0x12,0x32), BASE, ARG_OPRL }, + { "srl", OPR(0x12,0x34), BASE, ARG_OPR }, + { "srl", OPRL(0x12,0x34), BASE, ARG_OPRL }, + { "extql", OPR(0x12,0x36), BASE, ARG_OPR }, + { "extql", OPRL(0x12,0x36), BASE, ARG_OPRL }, + { "sll", OPR(0x12,0x39), BASE, ARG_OPR }, + { "sll", OPRL(0x12,0x39), BASE, ARG_OPRL }, + { "insql", OPR(0x12,0x3B), BASE, ARG_OPR }, + { "insql", OPRL(0x12,0x3B), BASE, ARG_OPRL }, + { "sra", OPR(0x12,0x3C), BASE, ARG_OPR }, + { "sra", OPRL(0x12,0x3C), BASE, ARG_OPRL }, + { "mskwh", OPR(0x12,0x52), BASE, ARG_OPR }, + { "mskwh", OPRL(0x12,0x52), BASE, ARG_OPRL }, + { "inswh", OPR(0x12,0x57), BASE, ARG_OPR }, + { "inswh", OPRL(0x12,0x57), BASE, ARG_OPRL }, + { "extwh", OPR(0x12,0x5A), BASE, ARG_OPR }, + { "extwh", OPRL(0x12,0x5A), BASE, ARG_OPRL }, + { "msklh", OPR(0x12,0x62), BASE, ARG_OPR }, + { "msklh", OPRL(0x12,0x62), BASE, ARG_OPRL }, + { "inslh", OPR(0x12,0x67), BASE, ARG_OPR }, + { "inslh", OPRL(0x12,0x67), BASE, ARG_OPRL }, + { "extlh", OPR(0x12,0x6A), BASE, ARG_OPR }, + { "extlh", OPRL(0x12,0x6A), BASE, ARG_OPRL }, + { "mskqh", OPR(0x12,0x72), BASE, ARG_OPR }, + { "mskqh", OPRL(0x12,0x72), BASE, ARG_OPRL }, + { "insqh", OPR(0x12,0x77), BASE, ARG_OPR }, + { "insqh", OPRL(0x12,0x77), BASE, ARG_OPRL }, + { "extqh", OPR(0x12,0x7A), BASE, ARG_OPR }, + { "extqh", OPRL(0x12,0x7A), BASE, ARG_OPRL }, + + { "mull", OPR(0x13,0x00), BASE, ARG_OPR }, + { "mull", OPRL(0x13,0x00), BASE, ARG_OPRL }, + { "mulq", OPR(0x13,0x20), BASE, ARG_OPR }, + { "mulq", OPRL(0x13,0x20), BASE, ARG_OPRL }, + { "umulh", OPR(0x13,0x30), BASE, ARG_OPR }, + { "umulh", OPRL(0x13,0x30), BASE, ARG_OPRL }, + { "mull/v", OPR(0x13,0x40), BASE, ARG_OPR }, + { "mull/v", OPRL(0x13,0x40), BASE, ARG_OPRL }, + { "mulq/v", OPR(0x13,0x60), BASE, ARG_OPR }, + { "mulq/v", OPRL(0x13,0x60), BASE, ARG_OPRL }, + + { "itofs", FP(0x14,0x004), CIX, { RA, ZB, FC } }, + { "sqrtf/c", FP(0x14,0x00A), CIX, ARG_FPZ1 }, + { "sqrts/c", FP(0x14,0x00B), CIX, ARG_FPZ1 }, + { "itoff", FP(0x14,0x014), CIX, { RA, ZB, FC } }, + { "itoft", FP(0x14,0x024), CIX, { RA, ZB, FC } }, + { "sqrtg/c", FP(0x14,0x02A), CIX, ARG_FPZ1 }, + { "sqrtt/c", FP(0x14,0x02B), CIX, ARG_FPZ1 }, + { "sqrts/m", FP(0x14,0x04B), CIX, ARG_FPZ1 }, + { "sqrtt/m", FP(0x14,0x06B), CIX, ARG_FPZ1 }, + { "sqrtf", FP(0x14,0x08A), CIX, ARG_FPZ1 }, + { "sqrts", FP(0x14,0x08B), CIX, ARG_FPZ1 }, + { "sqrtg", FP(0x14,0x0AA), CIX, ARG_FPZ1 }, + { "sqrtt", FP(0x14,0x0AB), CIX, ARG_FPZ1 }, + { "sqrts/d", FP(0x14,0x0CB), CIX, ARG_FPZ1 }, + { "sqrtt/d", FP(0x14,0x0EB), CIX, ARG_FPZ1 }, + { "sqrtf/uc", FP(0x14,0x10A), CIX, ARG_FPZ1 }, + { "sqrts/uc", FP(0x14,0x10B), CIX, ARG_FPZ1 }, + { "sqrtg/uc", FP(0x14,0x12A), CIX, ARG_FPZ1 }, + { "sqrtt/uc", FP(0x14,0x12B), CIX, ARG_FPZ1 }, + { "sqrts/um", FP(0x14,0x14B), CIX, ARG_FPZ1 }, + { "sqrtt/um", FP(0x14,0x16B), CIX, ARG_FPZ1 }, + { "sqrtf/u", FP(0x14,0x18A), CIX, ARG_FPZ1 }, + { "sqrts/u", FP(0x14,0x18B), CIX, ARG_FPZ1 }, + { "sqrtg/u", FP(0x14,0x1AA), CIX, ARG_FPZ1 }, + { "sqrtt/u", FP(0x14,0x1AB), CIX, ARG_FPZ1 }, + { "sqrts/ud", FP(0x14,0x1CB), CIX, ARG_FPZ1 }, + { "sqrtt/ud", FP(0x14,0x1EB), CIX, ARG_FPZ1 }, + { "sqrtf/sc", FP(0x14,0x40A), CIX, ARG_FPZ1 }, + { "sqrtg/sc", FP(0x14,0x42A), CIX, ARG_FPZ1 }, + { "sqrtf/s", FP(0x14,0x48A), CIX, ARG_FPZ1 }, + { "sqrtg/s", FP(0x14,0x4AA), CIX, ARG_FPZ1 }, + { "sqrtf/suc", FP(0x14,0x50A), CIX, ARG_FPZ1 }, + { "sqrts/suc", FP(0x14,0x50B), CIX, ARG_FPZ1 }, + { "sqrtg/suc", FP(0x14,0x52A), CIX, ARG_FPZ1 }, + { "sqrtt/suc", FP(0x14,0x52B), CIX, ARG_FPZ1 }, + { "sqrts/sum", FP(0x14,0x54B), CIX, ARG_FPZ1 }, + { "sqrtt/sum", FP(0x14,0x56B), CIX, ARG_FPZ1 }, + { "sqrtf/su", FP(0x14,0x58A), CIX, ARG_FPZ1 }, + { "sqrts/su", FP(0x14,0x58B), CIX, ARG_FPZ1 }, + { "sqrtg/su", FP(0x14,0x5AA), CIX, ARG_FPZ1 }, + { "sqrtt/su", FP(0x14,0x5AB), CIX, ARG_FPZ1 }, + { "sqrts/sud", FP(0x14,0x5CB), CIX, ARG_FPZ1 }, + { "sqrtt/sud", FP(0x14,0x5EB), CIX, ARG_FPZ1 }, + { "sqrts/suic", FP(0x14,0x70B), CIX, ARG_FPZ1 }, + { "sqrtt/suic", FP(0x14,0x72B), CIX, ARG_FPZ1 }, + { "sqrts/suim", FP(0x14,0x74B), CIX, ARG_FPZ1 }, + { "sqrtt/suim", FP(0x14,0x76B), CIX, ARG_FPZ1 }, + { "sqrts/sui", FP(0x14,0x78B), CIX, ARG_FPZ1 }, + { "sqrtt/sui", FP(0x14,0x7AB), CIX, ARG_FPZ1 }, + { "sqrts/suid", FP(0x14,0x7CB), CIX, ARG_FPZ1 }, + { "sqrtt/suid", FP(0x14,0x7EB), CIX, ARG_FPZ1 }, + + { "addf/c", FP(0x15,0x000), BASE, ARG_FP }, + { "subf/c", FP(0x15,0x001), BASE, ARG_FP }, + { "mulf/c", FP(0x15,0x002), BASE, ARG_FP }, + { "divf/c", FP(0x15,0x003), BASE, ARG_FP }, + { "cvtdg/c", FP(0x15,0x01E), BASE, ARG_FPZ1 }, + { "addg/c", FP(0x15,0x020), BASE, ARG_FP }, + { "subg/c", FP(0x15,0x021), BASE, ARG_FP }, + { "mulg/c", FP(0x15,0x022), BASE, ARG_FP }, + { "divg/c", FP(0x15,0x023), BASE, ARG_FP }, + { "cvtgf/c", FP(0x15,0x02C), BASE, ARG_FPZ1 }, + { "cvtgd/c", FP(0x15,0x02D), BASE, ARG_FPZ1 }, + { "cvtgq/c", FP(0x15,0x02F), BASE, ARG_FPZ1 }, + { "cvtqf/c", FP(0x15,0x03C), BASE, ARG_FPZ1 }, + { "cvtqg/c", FP(0x15,0x03E), BASE, ARG_FPZ1 }, + { "addf", FP(0x15,0x080), BASE, ARG_FP }, + { "negf", FP(0x15,0x081), BASE, ARG_FPZ1 }, /* pseudo */ + { "subf", FP(0x15,0x081), BASE, ARG_FP }, + { "mulf", FP(0x15,0x082), BASE, ARG_FP }, + { "divf", FP(0x15,0x083), BASE, ARG_FP }, + { "cvtdg", FP(0x15,0x09E), BASE, ARG_FPZ1 }, + { "addg", FP(0x15,0x0A0), BASE, ARG_FP }, + { "negg", FP(0x15,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subg", FP(0x15,0x0A1), BASE, ARG_FP }, + { "mulg", FP(0x15,0x0A2), BASE, ARG_FP }, + { "divg", FP(0x15,0x0A3), BASE, ARG_FP }, + { "cmpgeq", FP(0x15,0x0A5), BASE, ARG_FP }, + { "cmpglt", FP(0x15,0x0A6), BASE, ARG_FP }, + { "cmpgle", FP(0x15,0x0A7), BASE, ARG_FP }, + { "cvtgf", FP(0x15,0x0AC), BASE, ARG_FPZ1 }, + { "cvtgd", FP(0x15,0x0AD), BASE, ARG_FPZ1 }, + { "cvtgq", FP(0x15,0x0AF), BASE, ARG_FPZ1 }, + { "cvtqf", FP(0x15,0x0BC), BASE, ARG_FPZ1 }, + { "cvtqg", FP(0x15,0x0BE), BASE, ARG_FPZ1 }, + { "addf/uc", FP(0x15,0x100), BASE, ARG_FP }, + { "subf/uc", FP(0x15,0x101), BASE, ARG_FP }, + { "mulf/uc", FP(0x15,0x102), BASE, ARG_FP }, + { "divf/uc", FP(0x15,0x103), BASE, ARG_FP }, + { "cvtdg/uc", FP(0x15,0x11E), BASE, ARG_FPZ1 }, + { "addg/uc", FP(0x15,0x120), BASE, ARG_FP }, + { "subg/uc", FP(0x15,0x121), BASE, ARG_FP }, + { "mulg/uc", FP(0x15,0x122), BASE, ARG_FP }, + { "divg/uc", FP(0x15,0x123), BASE, ARG_FP }, + { "cvtgf/uc", FP(0x15,0x12C), BASE, ARG_FPZ1 }, + { "cvtgd/uc", FP(0x15,0x12D), BASE, ARG_FPZ1 }, + { "cvtgq/vc", FP(0x15,0x12F), BASE, ARG_FPZ1 }, + { "addf/u", FP(0x15,0x180), BASE, ARG_FP }, + { "subf/u", FP(0x15,0x181), BASE, ARG_FP }, + { "mulf/u", FP(0x15,0x182), BASE, ARG_FP }, + { "divf/u", FP(0x15,0x183), BASE, ARG_FP }, + { "cvtdg/u", FP(0x15,0x19E), BASE, ARG_FPZ1 }, + { "addg/u", FP(0x15,0x1A0), BASE, ARG_FP }, + { "subg/u", FP(0x15,0x1A1), BASE, ARG_FP }, + { "mulg/u", FP(0x15,0x1A2), BASE, ARG_FP }, + { "divg/u", FP(0x15,0x1A3), BASE, ARG_FP }, + { "cvtgf/u", FP(0x15,0x1AC), BASE, ARG_FPZ1 }, + { "cvtgd/u", FP(0x15,0x1AD), BASE, ARG_FPZ1 }, + { "cvtgq/v", FP(0x15,0x1AF), BASE, ARG_FPZ1 }, + { "addf/sc", FP(0x15,0x400), BASE, ARG_FP }, + { "subf/sc", FP(0x15,0x401), BASE, ARG_FP }, + { "mulf/sc", FP(0x15,0x402), BASE, ARG_FP }, + { "divf/sc", FP(0x15,0x403), BASE, ARG_FP }, + { "cvtdg/sc", FP(0x15,0x41E), BASE, ARG_FPZ1 }, + { "addg/sc", FP(0x15,0x420), BASE, ARG_FP }, + { "subg/sc", FP(0x15,0x421), BASE, ARG_FP }, + { "mulg/sc", FP(0x15,0x422), BASE, ARG_FP }, + { "divg/sc", FP(0x15,0x423), BASE, ARG_FP }, + { "cvtgf/sc", FP(0x15,0x42C), BASE, ARG_FPZ1 }, + { "cvtgd/sc", FP(0x15,0x42D), BASE, ARG_FPZ1 }, + { "cvtgq/sc", FP(0x15,0x42F), BASE, ARG_FPZ1 }, + { "addf/s", FP(0x15,0x480), BASE, ARG_FP }, + { "negf/s", FP(0x15,0x481), BASE, ARG_FPZ1 }, /* pseudo */ + { "subf/s", FP(0x15,0x481), BASE, ARG_FP }, + { "mulf/s", FP(0x15,0x482), BASE, ARG_FP }, + { "divf/s", FP(0x15,0x483), BASE, ARG_FP }, + { "cvtdg/s", FP(0x15,0x49E), BASE, ARG_FPZ1 }, + { "addg/s", FP(0x15,0x4A0), BASE, ARG_FP }, + { "negg/s", FP(0x15,0x4A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subg/s", FP(0x15,0x4A1), BASE, ARG_FP }, + { "mulg/s", FP(0x15,0x4A2), BASE, ARG_FP }, + { "divg/s", FP(0x15,0x4A3), BASE, ARG_FP }, + { "cmpgeq/s", FP(0x15,0x4A5), BASE, ARG_FP }, + { "cmpglt/s", FP(0x15,0x4A6), BASE, ARG_FP }, + { "cmpgle/s", FP(0x15,0x4A7), BASE, ARG_FP }, + { "cvtgf/s", FP(0x15,0x4AC), BASE, ARG_FPZ1 }, + { "cvtgd/s", FP(0x15,0x4AD), BASE, ARG_FPZ1 }, + { "cvtgq/s", FP(0x15,0x4AF), BASE, ARG_FPZ1 }, + { "addf/suc", FP(0x15,0x500), BASE, ARG_FP }, + { "subf/suc", FP(0x15,0x501), BASE, ARG_FP }, + { "mulf/suc", FP(0x15,0x502), BASE, ARG_FP }, + { "divf/suc", FP(0x15,0x503), BASE, ARG_FP }, + { "cvtdg/suc", FP(0x15,0x51E), BASE, ARG_FPZ1 }, + { "addg/suc", FP(0x15,0x520), BASE, ARG_FP }, + { "subg/suc", FP(0x15,0x521), BASE, ARG_FP }, + { "mulg/suc", FP(0x15,0x522), BASE, ARG_FP }, + { "divg/suc", FP(0x15,0x523), BASE, ARG_FP }, + { "cvtgf/suc", FP(0x15,0x52C), BASE, ARG_FPZ1 }, + { "cvtgd/suc", FP(0x15,0x52D), BASE, ARG_FPZ1 }, + { "cvtgq/svc", FP(0x15,0x52F), BASE, ARG_FPZ1 }, + { "addf/su", FP(0x15,0x580), BASE, ARG_FP }, + { "subf/su", FP(0x15,0x581), BASE, ARG_FP }, + { "mulf/su", FP(0x15,0x582), BASE, ARG_FP }, + { "divf/su", FP(0x15,0x583), BASE, ARG_FP }, + { "cvtdg/su", FP(0x15,0x59E), BASE, ARG_FPZ1 }, + { "addg/su", FP(0x15,0x5A0), BASE, ARG_FP }, + { "subg/su", FP(0x15,0x5A1), BASE, ARG_FP }, + { "mulg/su", FP(0x15,0x5A2), BASE, ARG_FP }, + { "divg/su", FP(0x15,0x5A3), BASE, ARG_FP }, + { "cvtgf/su", FP(0x15,0x5AC), BASE, ARG_FPZ1 }, + { "cvtgd/su", FP(0x15,0x5AD), BASE, ARG_FPZ1 }, + { "cvtgq/sv", FP(0x15,0x5AF), BASE, ARG_FPZ1 }, + + { "adds/c", FP(0x16,0x000), BASE, ARG_FP }, + { "subs/c", FP(0x16,0x001), BASE, ARG_FP }, + { "muls/c", FP(0x16,0x002), BASE, ARG_FP }, + { "divs/c", FP(0x16,0x003), BASE, ARG_FP }, + { "addt/c", FP(0x16,0x020), BASE, ARG_FP }, + { "subt/c", FP(0x16,0x021), BASE, ARG_FP }, + { "mult/c", FP(0x16,0x022), BASE, ARG_FP }, + { "divt/c", FP(0x16,0x023), BASE, ARG_FP }, + { "cvtts/c", FP(0x16,0x02C), BASE, ARG_FPZ1 }, + { "cvttq/c", FP(0x16,0x02F), BASE, ARG_FPZ1 }, + { "cvtqs/c", FP(0x16,0x03C), BASE, ARG_FPZ1 }, + { "cvtqt/c", FP(0x16,0x03E), BASE, ARG_FPZ1 }, + { "adds/m", FP(0x16,0x040), BASE, ARG_FP }, + { "subs/m", FP(0x16,0x041), BASE, ARG_FP }, + { "muls/m", FP(0x16,0x042), BASE, ARG_FP }, + { "divs/m", FP(0x16,0x043), BASE, ARG_FP }, + { "addt/m", FP(0x16,0x060), BASE, ARG_FP }, + { "subt/m", FP(0x16,0x061), BASE, ARG_FP }, + { "mult/m", FP(0x16,0x062), BASE, ARG_FP }, + { "divt/m", FP(0x16,0x063), BASE, ARG_FP }, + { "cvtts/m", FP(0x16,0x06C), BASE, ARG_FPZ1 }, + { "cvttq/m", FP(0x16,0x06F), BASE, ARG_FPZ1 }, + { "cvtqs/m", FP(0x16,0x07C), BASE, ARG_FPZ1 }, + { "cvtqt/m", FP(0x16,0x07E), BASE, ARG_FPZ1 }, + { "adds", FP(0x16,0x080), BASE, ARG_FP }, + { "negs", FP(0x16,0x081), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs", FP(0x16,0x081), BASE, ARG_FP }, + { "muls", FP(0x16,0x082), BASE, ARG_FP }, + { "divs", FP(0x16,0x083), BASE, ARG_FP }, + { "addt", FP(0x16,0x0A0), BASE, ARG_FP }, + { "negt", FP(0x16,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt", FP(0x16,0x0A1), BASE, ARG_FP }, + { "mult", FP(0x16,0x0A2), BASE, ARG_FP }, + { "divt", FP(0x16,0x0A3), BASE, ARG_FP }, + { "cmptun", FP(0x16,0x0A4), BASE, ARG_FP }, + { "cmpteq", FP(0x16,0x0A5), BASE, ARG_FP }, + { "cmptlt", FP(0x16,0x0A6), BASE, ARG_FP }, + { "cmptle", FP(0x16,0x0A7), BASE, ARG_FP }, + { "cvtts", FP(0x16,0x0AC), BASE, ARG_FPZ1 }, + { "cvttq", FP(0x16,0x0AF), BASE, ARG_FPZ1 }, + { "cvtqs", FP(0x16,0x0BC), BASE, ARG_FPZ1 }, + { "cvtqt", FP(0x16,0x0BE), BASE, ARG_FPZ1 }, + { "adds/d", FP(0x16,0x0C0), BASE, ARG_FP }, + { "subs/d", FP(0x16,0x0C1), BASE, ARG_FP }, + { "muls/d", FP(0x16,0x0C2), BASE, ARG_FP }, + { "divs/d", FP(0x16,0x0C3), BASE, ARG_FP }, + { "addt/d", FP(0x16,0x0E0), BASE, ARG_FP }, + { "subt/d", FP(0x16,0x0E1), BASE, ARG_FP }, + { "mult/d", FP(0x16,0x0E2), BASE, ARG_FP }, + { "divt/d", FP(0x16,0x0E3), BASE, ARG_FP }, + { "cvtts/d", FP(0x16,0x0EC), BASE, ARG_FPZ1 }, + { "cvttq/d", FP(0x16,0x0EF), BASE, ARG_FPZ1 }, + { "cvtqs/d", FP(0x16,0x0FC), BASE, ARG_FPZ1 }, + { "cvtqt/d", FP(0x16,0x0FE), BASE, ARG_FPZ1 }, + { "adds/uc", FP(0x16,0x100), BASE, ARG_FP }, + { "subs/uc", FP(0x16,0x101), BASE, ARG_FP }, + { "muls/uc", FP(0x16,0x102), BASE, ARG_FP }, + { "divs/uc", FP(0x16,0x103), BASE, ARG_FP }, + { "addt/uc", FP(0x16,0x120), BASE, ARG_FP }, + { "subt/uc", FP(0x16,0x121), BASE, ARG_FP }, + { "mult/uc", FP(0x16,0x122), BASE, ARG_FP }, + { "divt/uc", FP(0x16,0x123), BASE, ARG_FP }, + { "cvtts/uc", FP(0x16,0x12C), BASE, ARG_FPZ1 }, + { "cvttq/vc", FP(0x16,0x12F), BASE, ARG_FPZ1 }, + { "adds/um", FP(0x16,0x140), BASE, ARG_FP }, + { "subs/um", FP(0x16,0x141), BASE, ARG_FP }, + { "muls/um", FP(0x16,0x142), BASE, ARG_FP }, + { "divs/um", FP(0x16,0x143), BASE, ARG_FP }, + { "addt/um", FP(0x16,0x160), BASE, ARG_FP }, + { "subt/um", FP(0x16,0x161), BASE, ARG_FP }, + { "mult/um", FP(0x16,0x162), BASE, ARG_FP }, + { "divt/um", FP(0x16,0x163), BASE, ARG_FP }, + { "cvtts/um", FP(0x16,0x16C), BASE, ARG_FPZ1 }, + { "cvttq/vm", FP(0x16,0x16F), BASE, ARG_FPZ1 }, + { "adds/u", FP(0x16,0x180), BASE, ARG_FP }, + { "subs/u", FP(0x16,0x181), BASE, ARG_FP }, + { "muls/u", FP(0x16,0x182), BASE, ARG_FP }, + { "divs/u", FP(0x16,0x183), BASE, ARG_FP }, + { "addt/u", FP(0x16,0x1A0), BASE, ARG_FP }, + { "subt/u", FP(0x16,0x1A1), BASE, ARG_FP }, + { "mult/u", FP(0x16,0x1A2), BASE, ARG_FP }, + { "divt/u", FP(0x16,0x1A3), BASE, ARG_FP }, + { "cvtts/u", FP(0x16,0x1AC), BASE, ARG_FPZ1 }, + { "cvttq/v", FP(0x16,0x1AF), BASE, ARG_FPZ1 }, + { "adds/ud", FP(0x16,0x1C0), BASE, ARG_FP }, + { "subs/ud", FP(0x16,0x1C1), BASE, ARG_FP }, + { "muls/ud", FP(0x16,0x1C2), BASE, ARG_FP }, + { "divs/ud", FP(0x16,0x1C3), BASE, ARG_FP }, + { "addt/ud", FP(0x16,0x1E0), BASE, ARG_FP }, + { "subt/ud", FP(0x16,0x1E1), BASE, ARG_FP }, + { "mult/ud", FP(0x16,0x1E2), BASE, ARG_FP }, + { "divt/ud", FP(0x16,0x1E3), BASE, ARG_FP }, + { "cvtts/ud", FP(0x16,0x1EC), BASE, ARG_FPZ1 }, + { "cvttq/vd", FP(0x16,0x1EF), BASE, ARG_FPZ1 }, + { "cvtst", FP(0x16,0x2AC), BASE, ARG_FPZ1 }, + { "adds/suc", FP(0x16,0x500), BASE, ARG_FP }, + { "subs/suc", FP(0x16,0x501), BASE, ARG_FP }, + { "muls/suc", FP(0x16,0x502), BASE, ARG_FP }, + { "divs/suc", FP(0x16,0x503), BASE, ARG_FP }, + { "addt/suc", FP(0x16,0x520), BASE, ARG_FP }, + { "subt/suc", FP(0x16,0x521), BASE, ARG_FP }, + { "mult/suc", FP(0x16,0x522), BASE, ARG_FP }, + { "divt/suc", FP(0x16,0x523), BASE, ARG_FP }, + { "cvtts/suc", FP(0x16,0x52C), BASE, ARG_FPZ1 }, + { "cvttq/svc", FP(0x16,0x52F), BASE, ARG_FPZ1 }, + { "adds/sum", FP(0x16,0x540), BASE, ARG_FP }, + { "subs/sum", FP(0x16,0x541), BASE, ARG_FP }, + { "muls/sum", FP(0x16,0x542), BASE, ARG_FP }, + { "divs/sum", FP(0x16,0x543), BASE, ARG_FP }, + { "addt/sum", FP(0x16,0x560), BASE, ARG_FP }, + { "subt/sum", FP(0x16,0x561), BASE, ARG_FP }, + { "mult/sum", FP(0x16,0x562), BASE, ARG_FP }, + { "divt/sum", FP(0x16,0x563), BASE, ARG_FP }, + { "cvtts/sum", FP(0x16,0x56C), BASE, ARG_FPZ1 }, + { "cvttq/svm", FP(0x16,0x56F), BASE, ARG_FPZ1 }, + { "adds/su", FP(0x16,0x580), BASE, ARG_FP }, + { "negs/su", FP(0x16,0x581), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs/su", FP(0x16,0x581), BASE, ARG_FP }, + { "muls/su", FP(0x16,0x582), BASE, ARG_FP }, + { "divs/su", FP(0x16,0x583), BASE, ARG_FP }, + { "addt/su", FP(0x16,0x5A0), BASE, ARG_FP }, + { "negt/su", FP(0x16,0x5A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt/su", FP(0x16,0x5A1), BASE, ARG_FP }, + { "mult/su", FP(0x16,0x5A2), BASE, ARG_FP }, + { "divt/su", FP(0x16,0x5A3), BASE, ARG_FP }, + { "cmptun/su", FP(0x16,0x5A4), BASE, ARG_FP }, + { "cmpteq/su", FP(0x16,0x5A5), BASE, ARG_FP }, + { "cmptlt/su", FP(0x16,0x5A6), BASE, ARG_FP }, + { "cmptle/su", FP(0x16,0x5A7), BASE, ARG_FP }, + { "cvtts/su", FP(0x16,0x5AC), BASE, ARG_FPZ1 }, + { "cvttq/sv", FP(0x16,0x5AF), BASE, ARG_FPZ1 }, + { "adds/sud", FP(0x16,0x5C0), BASE, ARG_FP }, + { "subs/sud", FP(0x16,0x5C1), BASE, ARG_FP }, + { "muls/sud", FP(0x16,0x5C2), BASE, ARG_FP }, + { "divs/sud", FP(0x16,0x5C3), BASE, ARG_FP }, + { "addt/sud", FP(0x16,0x5E0), BASE, ARG_FP }, + { "subt/sud", FP(0x16,0x5E1), BASE, ARG_FP }, + { "mult/sud", FP(0x16,0x5E2), BASE, ARG_FP }, + { "divt/sud", FP(0x16,0x5E3), BASE, ARG_FP }, + { "cvtts/sud", FP(0x16,0x5EC), BASE, ARG_FPZ1 }, + { "cvttq/svd", FP(0x16,0x5EF), BASE, ARG_FPZ1 }, + { "cvtst/s", FP(0x16,0x6AC), BASE, ARG_FPZ1 }, + { "adds/suic", FP(0x16,0x700), BASE, ARG_FP }, + { "subs/suic", FP(0x16,0x701), BASE, ARG_FP }, + { "muls/suic", FP(0x16,0x702), BASE, ARG_FP }, + { "divs/suic", FP(0x16,0x703), BASE, ARG_FP }, + { "addt/suic", FP(0x16,0x720), BASE, ARG_FP }, + { "subt/suic", FP(0x16,0x721), BASE, ARG_FP }, + { "mult/suic", FP(0x16,0x722), BASE, ARG_FP }, + { "divt/suic", FP(0x16,0x723), BASE, ARG_FP }, + { "cvtts/suic", FP(0x16,0x72C), BASE, ARG_FPZ1 }, + { "cvttq/svic", FP(0x16,0x72F), BASE, ARG_FPZ1 }, + { "cvtqs/suic", FP(0x16,0x73C), BASE, ARG_FPZ1 }, + { "cvtqt/suic", FP(0x16,0x73E), BASE, ARG_FPZ1 }, + { "adds/suim", FP(0x16,0x740), BASE, ARG_FP }, + { "subs/suim", FP(0x16,0x741), BASE, ARG_FP }, + { "muls/suim", FP(0x16,0x742), BASE, ARG_FP }, + { "divs/suim", FP(0x16,0x743), BASE, ARG_FP }, + { "addt/suim", FP(0x16,0x760), BASE, ARG_FP }, + { "subt/suim", FP(0x16,0x761), BASE, ARG_FP }, + { "mult/suim", FP(0x16,0x762), BASE, ARG_FP }, + { "divt/suim", FP(0x16,0x763), BASE, ARG_FP }, + { "cvtts/suim", FP(0x16,0x76C), BASE, ARG_FPZ1 }, + { "cvttq/svim", FP(0x16,0x76F), BASE, ARG_FPZ1 }, + { "cvtqs/suim", FP(0x16,0x77C), BASE, ARG_FPZ1 }, + { "cvtqt/suim", FP(0x16,0x77E), BASE, ARG_FPZ1 }, + { "adds/sui", FP(0x16,0x780), BASE, ARG_FP }, + { "negs/sui", FP(0x16,0x781), BASE, ARG_FPZ1 }, /* pseudo */ + { "subs/sui", FP(0x16,0x781), BASE, ARG_FP }, + { "muls/sui", FP(0x16,0x782), BASE, ARG_FP }, + { "divs/sui", FP(0x16,0x783), BASE, ARG_FP }, + { "addt/sui", FP(0x16,0x7A0), BASE, ARG_FP }, + { "negt/sui", FP(0x16,0x7A1), BASE, ARG_FPZ1 }, /* pseudo */ + { "subt/sui", FP(0x16,0x7A1), BASE, ARG_FP }, + { "mult/sui", FP(0x16,0x7A2), BASE, ARG_FP }, + { "divt/sui", FP(0x16,0x7A3), BASE, ARG_FP }, + { "cvtts/sui", FP(0x16,0x7AC), BASE, ARG_FPZ1 }, + { "cvttq/svi", FP(0x16,0x7AF), BASE, ARG_FPZ1 }, + { "cvtqs/sui", FP(0x16,0x7BC), BASE, ARG_FPZ1 }, + { "cvtqt/sui", FP(0x16,0x7BE), BASE, ARG_FPZ1 }, + { "adds/suid", FP(0x16,0x7C0), BASE, ARG_FP }, + { "subs/suid", FP(0x16,0x7C1), BASE, ARG_FP }, + { "muls/suid", FP(0x16,0x7C2), BASE, ARG_FP }, + { "divs/suid", FP(0x16,0x7C3), BASE, ARG_FP }, + { "addt/suid", FP(0x16,0x7E0), BASE, ARG_FP }, + { "subt/suid", FP(0x16,0x7E1), BASE, ARG_FP }, + { "mult/suid", FP(0x16,0x7E2), BASE, ARG_FP }, + { "divt/suid", FP(0x16,0x7E3), BASE, ARG_FP }, + { "cvtts/suid", FP(0x16,0x7EC), BASE, ARG_FPZ1 }, + { "cvttq/svid", FP(0x16,0x7EF), BASE, ARG_FPZ1 }, + { "cvtqs/suid", FP(0x16,0x7FC), BASE, ARG_FPZ1 }, + { "cvtqt/suid", FP(0x16,0x7FE), BASE, ARG_FPZ1 }, + + { "cvtlq", FP(0x17,0x010), BASE, ARG_FPZ1 }, + { "fnop", FP(0x17,0x020), BASE, { ZA, ZB, ZC } }, /* pseudo */ + { "fclr", FP(0x17,0x020), BASE, { ZA, ZB, FC } }, /* pseudo */ + { "fabs", FP(0x17,0x020), BASE, ARG_FPZ1 }, /* pseudo */ + { "fmov", FP(0x17,0x020), BASE, { FA, RBA, FC } }, /* pseudo */ + { "cpys", FP(0x17,0x020), BASE, ARG_FP }, + { "fneg", FP(0x17,0x021), BASE, { FA, RBA, FC } }, /* pseudo */ + { "cpysn", FP(0x17,0x021), BASE, ARG_FP }, + { "cpyse", FP(0x17,0x022), BASE, ARG_FP }, + { "mt_fpcr", FP(0x17,0x024), BASE, { FA, RBA, RCA } }, + { "mf_fpcr", FP(0x17,0x025), BASE, { FA, RBA, RCA } }, + { "fcmoveq", FP(0x17,0x02A), BASE, ARG_FP }, + { "fcmovne", FP(0x17,0x02B), BASE, ARG_FP }, + { "fcmovlt", FP(0x17,0x02C), BASE, ARG_FP }, + { "fcmovge", FP(0x17,0x02D), BASE, ARG_FP }, + { "fcmovle", FP(0x17,0x02E), BASE, ARG_FP }, + { "fcmovgt", FP(0x17,0x02F), BASE, ARG_FP }, + { "cvtql", FP(0x17,0x030), BASE, ARG_FPZ1 }, + { "cvtql/v", FP(0x17,0x130), BASE, ARG_FPZ1 }, + { "cvtql/sv", FP(0x17,0x530), BASE, ARG_FPZ1 }, + + { "trapb", MFC(0x18,0x0000), BASE, ARG_NONE }, + { "draint", MFC(0x18,0x0000), BASE, ARG_NONE }, /* alias */ + { "excb", MFC(0x18,0x0400), BASE, ARG_NONE }, + { "mb", MFC(0x18,0x4000), BASE, ARG_NONE }, + { "wmb", MFC(0x18,0x4400), BASE, ARG_NONE }, + { "fetch", MFC(0x18,0x8000), BASE, { ZA, PRB } }, + { "fetch_m", MFC(0x18,0xA000), BASE, { ZA, PRB } }, + { "rpcc", MFC(0x18,0xC000), BASE, { RA } }, + { "rc", MFC(0x18,0xE000), BASE, { RA } }, + { "ecb", MFC(0x18,0xE800), BASE, { ZA, PRB } }, /* ev56 una */ + { "rs", MFC(0x18,0xF000), BASE, { RA } }, + { "wh64", MFC(0x18,0xF800), BASE, { ZA, PRB } }, /* ev56 una */ + { "wh64en", MFC(0x18,0xFC00), BASE, { ZA, PRB } }, /* ev7 una */ + + { "hw_mfpr", OPR(0x19,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } }, + { "hw_mfpr", OP(0x19), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } }, + { "hw_mfpr", OP(0x19), OP_MASK, EV6, { RA, ZB, EV6HWINDEX } }, + { "hw_mfpr/i", OPR(0x19,0x01), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/a", OPR(0x19,0x02), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/ai", OPR(0x19,0x03), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/p", OPR(0x19,0x04), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pi", OPR(0x19,0x05), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pa", OPR(0x19,0x06), EV4, ARG_EV4HWMPR }, + { "hw_mfpr/pai", OPR(0x19,0x07), EV4, ARG_EV4HWMPR }, + { "pal19", PCD(0x19), BASE, ARG_PCD }, + + { "jmp", MBR_(0x1A,0), MBR_MASK | 0x3FFF, /* pseudo */ + BASE, { ZA, CPRB } }, + { "jmp", MBR(0x1A,0), BASE, { RA, CPRB, JMPHINT } }, + { "jsr", MBR(0x1A,1), BASE, { RA, CPRB, JMPHINT } }, + { "ret", MBR_(0x1A,2) | (31 << 21) | (26 << 16) | 1,/* pseudo */ + 0xFFFFFFFF, BASE, { 0 } }, + { "ret", MBR(0x1A,2), BASE, { RA, CPRB, RETHINT } }, + { "jcr", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, /* alias */ + { "jsr_coroutine", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, + + { "hw_ldl", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM }, + { "hw_ldl", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM }, + { "hw_ldl", EV6HWMEM(0x1B,0x8), EV6, ARG_EV6HWMEM }, + { "hw_ldl/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM }, + { "hw_ldl/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM }, + { "hw_ldl/a", EV6HWMEM(0x1B,0xC), EV6, ARG_EV6HWMEM }, + { "hw_ldl/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ldl/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM }, + { "hw_ldl/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM }, + { "hw_ldl/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ldl/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ldl/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM }, + { "hw_ldl/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM }, + { "hw_ldl/p", EV6HWMEM(0x1B,0x0), EV6, ARG_EV6HWMEM }, + { "hw_ldl/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ldl/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ldl/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM }, + { "hw_ldl/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ldl/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM }, + { "hw_ldl/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM }, + { "hw_ldl/v", EV6HWMEM(0x1B,0x4), EV6, ARG_EV6HWMEM }, + { "hw_ldl/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ldl/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM }, + { "hw_ldl/w", EV6HWMEM(0x1B,0xA), EV6, ARG_EV6HWMEM }, + { "hw_ldl/wa", EV6HWMEM(0x1B,0xE), EV6, ARG_EV6HWMEM }, + { "hw_ldl/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ldl/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM }, + { "hw_ldl/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/a", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/av", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/aw", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/awv", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/p", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/p", EV6HWMEM(0x1B,0x2), EV6, ARG_EV6HWMEM }, + { "hw_ldl_l/pa", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pav", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/paw", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pawv", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pv", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pw", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/pwv", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/v", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/w", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ldl_l/wv", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "hw_ldq", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM }, + { "hw_ldq", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM }, + { "hw_ldq", EV6HWMEM(0x1B,0x9), EV6, ARG_EV6HWMEM }, + { "hw_ldq/a", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM }, + { "hw_ldq/a", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM }, + { "hw_ldq/a", EV6HWMEM(0x1B,0xD), EV6, ARG_EV6HWMEM }, + { "hw_ldq/al", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ldq/ar", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM }, + { "hw_ldq/av", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM }, + { "hw_ldq/avl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ldq/aw", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awl", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/awvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ldq/p", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM }, + { "hw_ldq/p", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM }, + { "hw_ldq/p", EV6HWMEM(0x1B,0x1), EV6, ARG_EV6HWMEM }, + { "hw_ldq/pa", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pa", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pal", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ldq/par", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pav", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pavl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ldq/paw", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawl", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pawvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pl", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pr", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM }, + { "hw_ldq/pv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pw", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwl", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/pwvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ldq/r", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM }, + { "hw_ldq/v", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM }, + { "hw_ldq/v", EV6HWMEM(0x1B,0x5), EV6, ARG_EV6HWMEM }, + { "hw_ldq/vl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ldq/w", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM }, + { "hw_ldq/w", EV6HWMEM(0x1B,0xB), EV6, ARG_EV6HWMEM }, + { "hw_ldq/wa", EV6HWMEM(0x1B,0xF), EV6, ARG_EV6HWMEM }, + { "hw_ldq/wl", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ldq/wv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM }, + { "hw_ldq/wvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/a", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/av", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/aw", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/awv", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/p", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/p", EV6HWMEM(0x1B,0x3), EV6, ARG_EV6HWMEM }, + { "hw_ldq_l/pa", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pav", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/paw", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pawv", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pv", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pw", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/pwv", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/v", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/w", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ldq_l/wv", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ld", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM }, + { "hw_ld", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM }, + { "hw_ld/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM }, + { "hw_ld/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM }, + { "hw_ld/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM }, + { "hw_ld/aq", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM }, + { "hw_ld/aq", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM }, + { "hw_ld/aql", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM }, + { "hw_ld/aqv", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM }, + { "hw_ld/aqvl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM }, + { "hw_ld/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM }, + { "hw_ld/arq", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM }, + { "hw_ld/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM }, + { "hw_ld/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM }, + { "hw_ld/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM }, + { "hw_ld/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM }, + { "hw_ld/awq", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM }, + { "hw_ld/awql", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM }, + { "hw_ld/awqv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM }, + { "hw_ld/awqvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM }, + { "hw_ld/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM }, + { "hw_ld/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM }, + { "hw_ld/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM }, + { "hw_ld/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM }, + { "hw_ld/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM }, + { "hw_ld/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM }, + { "hw_ld/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM }, + { "hw_ld/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM }, + { "hw_ld/paq", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM }, + { "hw_ld/paq", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM }, + { "hw_ld/paql", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM }, + { "hw_ld/paqv", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM }, + { "hw_ld/paqvl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM }, + { "hw_ld/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM }, + { "hw_ld/parq", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM }, + { "hw_ld/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM }, + { "hw_ld/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM }, + { "hw_ld/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawq", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawql", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawqv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawqvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM }, + { "hw_ld/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM }, + { "hw_ld/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM }, + { "hw_ld/pq", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM }, + { "hw_ld/pq", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM }, + { "hw_ld/pql", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM }, + { "hw_ld/pqv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM }, + { "hw_ld/pqvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM }, + { "hw_ld/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM }, + { "hw_ld/prq", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM }, + { "hw_ld/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM }, + { "hw_ld/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM }, + { "hw_ld/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwq", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwql", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwqv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwqvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM }, + { "hw_ld/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM }, + { "hw_ld/q", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM }, + { "hw_ld/q", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM }, + { "hw_ld/ql", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM }, + { "hw_ld/qv", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM }, + { "hw_ld/qvl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM }, + { "hw_ld/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM }, + { "hw_ld/rq", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM }, + { "hw_ld/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM }, + { "hw_ld/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM }, + { "hw_ld/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM }, + { "hw_ld/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM }, + { "hw_ld/wq", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM }, + { "hw_ld/wql", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM }, + { "hw_ld/wqv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM }, + { "hw_ld/wqvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM }, + { "hw_ld/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM }, + { "hw_ld/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM }, + { "pal1b", PCD(0x1B), BASE, ARG_PCD }, + + { "sextb", OPR(0x1C, 0x00), BWX, ARG_OPRZ1 }, + { "sextw", OPR(0x1C, 0x01), BWX, ARG_OPRZ1 }, + { "ctpop", OPR(0x1C, 0x30), CIX, ARG_OPRZ1 }, + { "perr", OPR(0x1C, 0x31), MAX, ARG_OPR }, + { "ctlz", OPR(0x1C, 0x32), CIX, ARG_OPRZ1 }, + { "cttz", OPR(0x1C, 0x33), CIX, ARG_OPRZ1 }, + { "unpkbw", OPR(0x1C, 0x34), MAX, ARG_OPRZ1 }, + { "unpkbl", OPR(0x1C, 0x35), MAX, ARG_OPRZ1 }, + { "pkwb", OPR(0x1C, 0x36), MAX, ARG_OPRZ1 }, + { "pklb", OPR(0x1C, 0x37), MAX, ARG_OPRZ1 }, + { "minsb8", OPR(0x1C, 0x38), MAX, ARG_OPR }, + { "minsb8", OPRL(0x1C, 0x38), MAX, ARG_OPRL }, + { "minsw4", OPR(0x1C, 0x39), MAX, ARG_OPR }, + { "minsw4", OPRL(0x1C, 0x39), MAX, ARG_OPRL }, + { "minub8", OPR(0x1C, 0x3A), MAX, ARG_OPR }, + { "minub8", OPRL(0x1C, 0x3A), MAX, ARG_OPRL }, + { "minuw4", OPR(0x1C, 0x3B), MAX, ARG_OPR }, + { "minuw4", OPRL(0x1C, 0x3B), MAX, ARG_OPRL }, + { "maxub8", OPR(0x1C, 0x3C), MAX, ARG_OPR }, + { "maxub8", OPRL(0x1C, 0x3C), MAX, ARG_OPRL }, + { "maxuw4", OPR(0x1C, 0x3D), MAX, ARG_OPR }, + { "maxuw4", OPRL(0x1C, 0x3D), MAX, ARG_OPRL }, + { "maxsb8", OPR(0x1C, 0x3E), MAX, ARG_OPR }, + { "maxsb8", OPRL(0x1C, 0x3E), MAX, ARG_OPRL }, + { "maxsw4", OPR(0x1C, 0x3F), MAX, ARG_OPR }, + { "maxsw4", OPRL(0x1C, 0x3F), MAX, ARG_OPRL }, + { "ftoit", FP(0x1C, 0x70), CIX, { FA, ZB, RC } }, + { "ftois", FP(0x1C, 0x78), CIX, { FA, ZB, RC } }, + + { "hw_mtpr", OPR(0x1D,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } }, + { "hw_mtpr", OP(0x1D), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } }, + { "hw_mtpr", OP(0x1D), OP_MASK, EV6, { ZA, RB, EV6HWINDEX } }, + { "hw_mtpr/i", OPR(0x1D,0x01), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/a", OPR(0x1D,0x02), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/ai", OPR(0x1D,0x03), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/p", OPR(0x1D,0x04), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pi", OPR(0x1D,0x05), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pa", OPR(0x1D,0x06), EV4, ARG_EV4HWMPR }, + { "hw_mtpr/pai", OPR(0x1D,0x07), EV4, ARG_EV4HWMPR }, + { "pal1d", PCD(0x1D), BASE, ARG_PCD }, + + { "hw_rei", SPCD(0x1E,0x3FF8000), EV4|EV5, ARG_NONE }, + { "hw_rei_stall", SPCD(0x1E,0x3FFC000), EV5, ARG_NONE }, + { "hw_jmp", EV6HWMBR(0x1E,0x0), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_jsr", EV6HWMBR(0x1E,0x2), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_ret", EV6HWMBR(0x1E,0x4), EV6, { ZA, PRB } }, + { "hw_jcr", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, + { "hw_coroutine", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, /* alias */ + { "hw_jmp/stall", EV6HWMBR(0x1E,0x1), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_jsr/stall", EV6HWMBR(0x1E,0x3), EV6, { ZA, PRB, EV6HWJMPHINT } }, + { "hw_ret/stall", EV6HWMBR(0x1E,0x5), EV6, { ZA, PRB } }, + { "hw_jcr/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, + { "hw_coroutine/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, /* alias */ + { "pal1e", PCD(0x1E), BASE, ARG_PCD }, + + { "hw_stl", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM }, + { "hw_stl", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM }, + { "hw_stl", EV6HWMEM(0x1F,0x4), EV6, ARG_EV6HWMEM }, /* ??? 8 */ + { "hw_stl/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM }, + { "hw_stl/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM }, + { "hw_stl/a", EV6HWMEM(0x1F,0xC), EV6, ARG_EV6HWMEM }, + { "hw_stl/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_stl/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM }, + { "hw_stl/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM }, + { "hw_stl/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_stl/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_stl/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM }, + { "hw_stl/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM }, + { "hw_stl/p", EV6HWMEM(0x1F,0x0), EV6, ARG_EV6HWMEM }, + { "hw_stl/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM }, + { "hw_stl/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM }, + { "hw_stl/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_stl/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM }, + { "hw_stl/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_stl/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_stl/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM }, + { "hw_stl/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM }, + { "hw_stl/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_stl/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM }, + { "hw_stl/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM }, + { "hw_stl/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "hw_stl_c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/a", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/av", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/p", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/p", EV6HWMEM(0x1F,0x2), EV6, ARG_EV6HWMEM }, + { "hw_stl_c/pa", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/pav", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/pv", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_stl_c/v", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "hw_stq", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM }, + { "hw_stq", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM }, + { "hw_stq", EV6HWMEM(0x1F,0x5), EV6, ARG_EV6HWMEM }, /* ??? 9 */ + { "hw_stq/a", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM }, + { "hw_stq/a", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM }, + { "hw_stq/a", EV6HWMEM(0x1F,0xD), EV6, ARG_EV6HWMEM }, + { "hw_stq/ac", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_stq/ar", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM }, + { "hw_stq/av", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM }, + { "hw_stq/avc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_stq/c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_stq/p", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM }, + { "hw_stq/p", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM }, + { "hw_stq/p", EV6HWMEM(0x1F,0x1), EV6, ARG_EV6HWMEM }, + { "hw_stq/pa", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM }, + { "hw_stq/pa", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM }, + { "hw_stq/pac", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_stq/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM }, + { "hw_stq/par", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM }, + { "hw_stq/pav", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM }, + { "hw_stq/pavc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_stq/pc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_stq/pr", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM }, + { "hw_stq/pv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM }, + { "hw_stq/pvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_stq/r", EV4HWMEM(0x1F,0x3), EV4, ARG_EV4HWMEM }, + { "hw_stq/v", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM }, + { "hw_stq/vc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_stq_c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/a", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/av", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/p", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/p", EV6HWMEM(0x1F,0x3), EV6, ARG_EV6HWMEM }, + { "hw_stq_c/pa", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/pav", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/pv", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_stq_c/v", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_st", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM }, + { "hw_st", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM }, + { "hw_st/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM }, + { "hw_st/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM }, + { "hw_st/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM }, + { "hw_st/aq", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM }, + { "hw_st/aq", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM }, + { "hw_st/aqc", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM }, + { "hw_st/aqv", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM }, + { "hw_st/aqvc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM }, + { "hw_st/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM }, + { "hw_st/arq", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM }, + { "hw_st/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM }, + { "hw_st/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM }, + { "hw_st/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM }, + { "hw_st/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM }, + { "hw_st/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM }, + { "hw_st/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM }, + { "hw_st/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM }, + { "hw_st/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM }, + { "hw_st/paq", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM }, + { "hw_st/paq", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM }, + { "hw_st/paqc", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM }, + { "hw_st/paqv", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM }, + { "hw_st/paqvc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM }, + { "hw_st/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM }, + { "hw_st/parq", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM }, + { "hw_st/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM }, + { "hw_st/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM }, + { "hw_st/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM }, + { "hw_st/pq", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM }, + { "hw_st/pq", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM }, + { "hw_st/pqc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM }, + { "hw_st/pqv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM }, + { "hw_st/pqvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM }, + { "hw_st/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM }, + { "hw_st/prq", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM }, + { "hw_st/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM }, + { "hw_st/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM }, + { "hw_st/q", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM }, + { "hw_st/q", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM }, + { "hw_st/qc", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM }, + { "hw_st/qv", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM }, + { "hw_st/qvc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM }, + { "hw_st/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM }, + { "hw_st/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM }, + { "hw_st/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM }, + { "pal1f", PCD(0x1F), BASE, ARG_PCD }, + + { "ldf", MEM(0x20), BASE, ARG_FMEM }, + { "ldg", MEM(0x21), BASE, ARG_FMEM }, + { "lds", MEM(0x22), BASE, ARG_FMEM }, + { "ldt", MEM(0x23), BASE, ARG_FMEM }, + { "stf", MEM(0x24), BASE, ARG_FMEM }, + { "stg", MEM(0x25), BASE, ARG_FMEM }, + { "sts", MEM(0x26), BASE, ARG_FMEM }, + { "stt", MEM(0x27), BASE, ARG_FMEM }, + + { "ldl", MEM(0x28), BASE, ARG_MEM }, + { "ldq", MEM(0x29), BASE, ARG_MEM }, + { "ldl_l", MEM(0x2A), BASE, ARG_MEM }, + { "ldq_l", MEM(0x2B), BASE, ARG_MEM }, + { "stl", MEM(0x2C), BASE, ARG_MEM }, + { "stq", MEM(0x2D), BASE, ARG_MEM }, + { "stl_c", MEM(0x2E), BASE, ARG_MEM }, + { "stq_c", MEM(0x2F), BASE, ARG_MEM }, + + { "br", BRA(0x30), BASE, { ZA, BDISP } }, /* pseudo */ + { "br", BRA(0x30), BASE, ARG_BRA }, + { "fbeq", BRA(0x31), BASE, ARG_FBRA }, + { "fblt", BRA(0x32), BASE, ARG_FBRA }, + { "fble", BRA(0x33), BASE, ARG_FBRA }, + { "bsr", BRA(0x34), BASE, ARG_BRA }, + { "fbne", BRA(0x35), BASE, ARG_FBRA }, + { "fbge", BRA(0x36), BASE, ARG_FBRA }, + { "fbgt", BRA(0x37), BASE, ARG_FBRA }, + { "blbc", BRA(0x38), BASE, ARG_BRA }, + { "beq", BRA(0x39), BASE, ARG_BRA }, + { "blt", BRA(0x3A), BASE, ARG_BRA }, + { "ble", BRA(0x3B), BASE, ARG_BRA }, + { "blbs", BRA(0x3C), BASE, ARG_BRA }, + { "bne", BRA(0x3D), BASE, ARG_BRA }, + { "bge", BRA(0x3E), BASE, ARG_BRA }, + { "bgt", BRA(0x3F), BASE, ARG_BRA }, +}; + +const unsigned alpha_num_opcodes = sizeof(alpha_opcodes)/sizeof(*alpha_opcodes); + +/* OSF register names. */ + +static const char * const osf_regnames[64] = { + "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +/* VMS register names. */ + +static const char * const vms_regnames[64] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", + "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", + "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", + "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", + "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" +}; + +/* Disassemble Alpha instructions. */ + +int +print_insn_alpha (bfd_vma memaddr, struct disassemble_info *info) +{ + static const struct alpha_opcode *opcode_index[AXP_NOPS+1]; + const char * const * regnames; + const struct alpha_opcode *opcode, *opcode_end; + const unsigned char *opindex; + unsigned insn, op, isa_mask; + int need_comma; + + /* Initialize the majorop table the first time through */ + if (!opcode_index[0]) + { + opcode = alpha_opcodes; + opcode_end = opcode + alpha_num_opcodes; + + for (op = 0; op < AXP_NOPS; ++op) + { + opcode_index[op] = opcode; + while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) + ++opcode; + } + opcode_index[op] = opcode; + } + + if (info->flavour == bfd_target_evax_flavour) + regnames = vms_regnames; + else + regnames = osf_regnames; + + isa_mask = AXP_OPCODE_NOPAL; + switch (info->mach) + { + case bfd_mach_alpha_ev4: + isa_mask |= AXP_OPCODE_EV4; + break; + case bfd_mach_alpha_ev5: + isa_mask |= AXP_OPCODE_EV5; + break; + case bfd_mach_alpha_ev6: + isa_mask |= AXP_OPCODE_EV6; + break; + } + + /* Read the insn into a host word */ + { + bfd_byte buffer[4]; + int status = (*info->read_memory_func) (memaddr, buffer, 4, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + insn = bfd_getl32 (buffer); + } + + /* Get the major opcode of the instruction. */ + op = AXP_OP (insn); + + /* Find the first match in the opcode table. */ + opcode_end = opcode_index[op + 1]; + for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) + { + if ((insn ^ opcode->opcode) & opcode->mask) + continue; + + if (!(opcode->flags & isa_mask)) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + { + int invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + const struct alpha_operand *operand = alpha_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, &invalid); + } + if (invalid) + continue; + } + + /* The instruction is valid. */ + goto found; + } + + /* No instruction found */ + (*info->fprintf_func) (info->stream, ".long %#08x", insn); + + return 4; + +found: + (*info->fprintf_func) (info->stream, "%s", opcode->name); + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "\t"); + + /* Now extract and print the operands. */ + need_comma = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + const struct alpha_operand *operand = alpha_operands + *opindex; + int value; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & AXP_OPERAND_FAKE) != 0) + continue; + + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, (int *) NULL); + else + { + value = (insn >> operand->shift) & ((1 << operand->bits) - 1); + if (operand->flags & AXP_OPERAND_SIGNED) + { + int signbit = 1 << (operand->bits - 1); + value = (value ^ signbit) - signbit; + } + } + + if (need_comma && + ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA)) + != AXP_OPERAND_PARENS)) + { + (*info->fprintf_func) (info->stream, ","); + } + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, "("); + + /* Print the operand as directed by the flags. */ + if (operand->flags & AXP_OPERAND_IR) + (*info->fprintf_func) (info->stream, "%s", regnames[value]); + else if (operand->flags & AXP_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); + else if (operand->flags & AXP_OPERAND_RELATIVE) + (*info->print_address_func) (memaddr + 4 + value, info); + else if (operand->flags & AXP_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%d", value); + else + (*info->fprintf_func) (info->stream, "%#x", value); + + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, ")"); + need_comma = 1; + } + + return 4; +} diff --git a/qemu/qemu-git/alpha.ld b/qemu/qemu-git/alpha.ld new file mode 100644 index 0000000..906d76b --- /dev/null +++ b/qemu/qemu-git/alpha.ld @@ -0,0 +1,127 @@ +OUTPUT_FORMAT("elf64-alpha", "elf64-alpha", + "elf64-alpha") +OUTPUT_ARCH(alpha) +ENTRY(__start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/arm-dis.c b/qemu/qemu-git/arm-dis.c new file mode 100644 index 0000000..2c67d8f --- /dev/null +++ b/qemu/qemu-git/arm-dis.c @@ -0,0 +1,4117 @@ +/* Instruction printing code for the ARM + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + 2007, Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) + Modification by James G. Smith (jsmith@cygnus.co.uk) + + This file is part of libopcodes. + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Start of qemu specific additions. Mostly this is stub definitions + for things we don't care about. */ + +#include "dis-asm.h" +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') + +#define ARM_EXT_V1 0 +#define ARM_EXT_V2 0 +#define ARM_EXT_V2S 0 +#define ARM_EXT_V3 0 +#define ARM_EXT_V3M 0 +#define ARM_EXT_V4 0 +#define ARM_EXT_V4T 0 +#define ARM_EXT_V5 0 +#define ARM_EXT_V5T 0 +#define ARM_EXT_V5ExP 0 +#define ARM_EXT_V5E 0 +#define ARM_EXT_V5J 0 +#define ARM_EXT_V6 0 +#define ARM_EXT_V6K 0 +#define ARM_EXT_V6Z 0 +#define ARM_EXT_V6T2 0 +#define ARM_EXT_V7 0 +#define ARM_EXT_DIV 0 + +/* Co-processor space extensions. */ +#define ARM_CEXT_XSCALE 0 +#define ARM_CEXT_MAVERICK 0 +#define ARM_CEXT_IWMMXT 0 + +#define FPU_FPA_EXT_V1 0 +#define FPU_FPA_EXT_V2 0 +#define FPU_VFP_EXT_NONE 0 +#define FPU_VFP_EXT_V1xD 0 +#define FPU_VFP_EXT_V1 0 +#define FPU_VFP_EXT_V2 0 +#define FPU_MAVERICK 0 +#define FPU_VFP_EXT_V3 0 +#define FPU_NEON_EXT_V1 0 + +int floatformat_ieee_single_little; +/* Assume host uses ieee float. */ +static void floatformat_to_double (int *ignored, unsigned char *data, + double *dest) +{ + union { + uint32_t i; + float f; + } u; + u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + *dest = u.f; +} + +/* End of qemu specific additions. */ + +/* FIXME: Belongs in global header. */ +#ifndef strneq +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) +#endif + +#ifndef NUM_ELEM +#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) +#endif + +struct opcode32 +{ + unsigned long arch; /* Architecture defining this insn. */ + unsigned long value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ +}; + +struct opcode16 +{ + unsigned long arch; /* Architecture defining this insn. */ + unsigned short value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ +}; + +/* print_insn_coprocessor recognizes the following format control codes: + + %% % + + %c print condition code (always bits 28-31 in ARM mode) + %q print shifter argument + %u print condition code (unconditional in ARM mode) + %A print address for ldc/stc/ldf/stf instruction + %B print vstm/vldm register list + %C print vstr/vldr address operand + %I print cirrus signed shift immediate: bits 0..3|4..6 + %F print the COUNT field of a LFM/SFM instruction. + %P print floating point precision in arithmetic insn + %Q print floating point precision in ldf/stf insn + %R print floating point rounding mode + + %r print as an ARM register + %d print the bitfield in decimal + %k print immediate for VFPv3 conversion instruction + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + %f print a floating point constant if >7 else a + floating point register + %w print as an iWMMXt width field - [bhwd]ss/us + %g print as an iWMMXt 64-bit register + %G print as an iWMMXt general purpose or control register + %D print as a NEON D register + %Q print as a NEON Q register + + %y print a single precision VFP reg. + Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair + %z print a double precision VFP reg + Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %L print as an iWMMXt N/M width field. + %Z print the Immediate of a WSHUFH instruction. + %l like 'A' except use byte offsets for 'B' & 'H' + versions. + %i print 5-bit immediate in bits 8,3..0 + (print "32" when 0) + %r print register offset address for wldt/wstr instruction +*/ + +/* Common coprocessor opcodes shared between Arm and Thumb-2. */ + +static const struct opcode32 coprocessor_opcodes[] = +{ + /* XScale instructions. */ + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, + + /* Intel Wireless MMX technology instructions. */ +#define FIRST_IWMMXT_INSN 0x0e130130 +#define IWMMXT_INSN_COUNT 73 + {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"}, + {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"}, + {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"}, + {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"}, + + /* Floating point coprocessor (FPA) instructions */ + {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, + {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, + {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, + {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, + + /* Register load/store */ + {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"}, + {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"}, + + /* Data transfer between ARM and NEON registers */ + {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"}, + {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"}, + {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"}, + {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"}, + + /* Floating point coprocessor (VFP) instructions */ + {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, + {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, + {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"}, + {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"}, + {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, + {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, + {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, "}, + {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"}, + {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"}, + {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"}, + {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"}, + {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"}, + {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"}, + {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"}, + + /* Cirrus coprocessor instructions. */ + {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"}, + {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"}, + {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + + /* Generic coprocessor instructions */ + {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"}, + + /* V6 coprocessor instructions */ + {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + + /* V5 coprocessor instructions */ + {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + + {0, 0, 0, 0} +}; + +/* Neon opcode table: This does not encode the top byte -- that is + checked by the print_insn_neon routine, as it depends on whether we are + doing thumb32 or arm32 disassembly. */ + +/* print_insn_neon recognizes the following format control codes: + + %% % + + %c print condition code + %A print v{st,ld}[1234] operands + %B print v{st,ld}[1234] any one operands + %C print v{st,ld}[1234] single->all operands + %D print scalar + %E print vmov, vmvn, vorr, vbic encoded constant + %F print vtbl,vtbx register list + + %r print as an ARM register + %d print the bitfield in decimal + %e print the 2^N - bitfield in decimal + %D print as a NEON D register + %Q print as a NEON Q register + %R print as a NEON D or Q register + %Sn print byte scaled width limited by n + %Tn print short scaled width limited by n + %Un print long scaled width limited by n + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order */ + +static const struct opcode32 neon_opcodes[] = +{ + /* Extract */ + {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + + /* Move data element to all lanes */ + {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"}, + {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"}, + {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"}, + + /* Table lookup */ + {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"}, + + /* Two registers, miscellaneous */ + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"}, + {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, + + /* Three registers of the same length */ + {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + + /* One register and an immediate value */ + {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"}, + + /* Two registers and a shift amount */ + {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"}, + + /* Three registers of different lengths */ + {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + + /* Two registers and a scalar */ + {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + + /* Element and structure load/store */ + {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"}, + + {0,0 ,0, 0} +}; + +/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially + ordered: they must be searched linearly from the top to obtain a correct + match. */ + +/* print_insn_arm recognizes the following format control codes: + + %% % + + %a print address for ldr/str instruction + %s print address for ldr/str halfword/signextend instruction + %b print branch destination + %c print condition code (always bits 28-31) + %m print register mask for ldm/stm instruction + %o print operand2 (immediate or register + shift) + %p print 'p' iff bits 12-15 are 15 + %t print 't' iff bit 21 set and bit 24 clear + %B print arm BLX(1) destination + %C print the PSR sub type. + %U print barrier type. + %P print address for pli instruction. + + %r print as an ARM register + %d print the bitfield in decimal + %W print the bitfield plus one in decimal + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %e print arm SMI operand (bits 0..7,8..19). + %E print the LSB and WIDTH fields of a BFI or BFC instruction. + %V print the 16-bit immediate field of a MOVT or MOVW instruction. */ + +static const struct opcode32 arm_opcodes[] = +{ + /* ARM instructions. */ + {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, + {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, + {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + /* V7 instructions. */ + {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, + {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, + {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, + {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"}, + {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"}, + {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"}, + + /* ARM V6Z instructions. */ + {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"}, + + /* ARM V6K instructions. */ + {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"}, + {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"}, + + /* ARM V6K NOP hints. */ + {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"}, + {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"}, + {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"}, + {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"}, + {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"}, + + /* ARM V6 instructions. */ + {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"}, + {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"}, + {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"}, + {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"}, + {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"}, + {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"}, + + /* V5J instruction. */ + {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, + + /* V5 Instructions. */ + {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, + {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"}, + {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, + {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, + + /* V5E "El Segundo" Instructions. */ + {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"}, + {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, + + /* ARM Instructions. */ + {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, + {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, + {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"}, + {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"}, + {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"}, + {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, + {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"}, + + /* The rest. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"}, + {0, 0x00000000, 0x00000000, 0} +}; + +/* print_insn_thumb16 recognizes the following format control codes: + + %S print Thumb register (bits 3..5 as high number if bit 6 set) + %D print Thumb register (bits 0..2 as high number if bit 7 set) + %I print bitfield as a signed decimal + (top bit of range being the sign bit) + %N print Thumb register mask (with LR) + %O print Thumb register mask (with PC) + %M print Thumb register mask + %b print CZB's 6-bit unsigned branch destination + %s print Thumb right-shift immediate (6..10; 0 == 32). + %c print the condition code + %C print the condition code, or "s" if not conditional + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + %I print IT instruction suffix and operands + %r print bitfield as an ARM register + %d print bitfield as a decimal + %H print (bitfield * 2) as a decimal + %W print (bitfield * 4) as a decimal + %a print (bitfield * 4) as a pc-rel offset + decoded symbol + %B print Thumb branch destination (signed displacement) + %c print bitfield as a condition code + %'c print specified char iff bit is one + %?ab print a if bit is one else print b. */ + +static const struct opcode16 thumb_opcodes[] = +{ + /* Thumb instructions. */ + + /* ARM V6K no-argument instructions. */ + {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, + {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, + {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"}, + {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"}, + {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"}, + {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"}, + + /* ARM V6. */ + {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"}, + {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"}, + + /* ARM V5 ISA extends Thumb. */ + {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional. */ + /* This is BLX(2). BLX(1) is a 32-bit instruction. */ + {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"}, /* note: 4 bit register number. */ + /* ARM V4T ISA (Thumb v1). */ + {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"}, + /* Format 4. */ + {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"}, + /* format 13 */ + {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"}, + {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\tsp, #%0-6W"}, + /* format 5 */ + {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"}, + {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"}, + /* format 14 */ + {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"}, + {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\t%O"}, + /* format 2 */ + {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"}, + {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\t%0-2r, %3-5r, #%6-8d"}, + /* format 8 */ + {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\t%0-2r, [%3-5r, %6-8r]"}, + /* format 7 */ + {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, + /* format 1 */ + {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"}, + {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"}, + {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"}, + /* format 3 */ + {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\t%8-10r, #%0-7d"}, + /* format 6 */ + {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=" */ + /* format 9 */ + {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"}, + {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\t%0-2r, [%3-5r, #%6-10d]"}, + /* format 10 */ + {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"}, + {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\t%0-2r, [%3-5r, #%6-10H]"}, + /* format 11 */ + {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"}, + {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\t%8-10r, [sp, #%0-7W]"}, + /* format 12 */ + {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"}, + {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"}, + /* format 15 */ + {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"}, + {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"}, + /* format 17 */ + {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"}, + /* format 16 */ + {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"}, + {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"}, + /* format 18 */ + {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"}, + + /* The E800 .. FFFF range is unconditionally redirected to the + 32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs + are processed via that table. Thus, we can never encounter a + bare "second half of BL/BLX(1)" instruction here. */ + {ARM_EXT_V1, 0x0000, 0x0000, "undefined"}, + {0, 0, 0, 0} +}; + +/* Thumb32 opcodes use the same table structure as the ARM opcodes. + We adopt the convention that hw1 is the high 16 bits of .value and + .mask, hw2 the low 16 bits. + + print_insn_thumb32 recognizes the following format control codes: + + %% % + + %I print a 12-bit immediate from hw1[10],hw2[14:12,7:0] + %M print a modified 12-bit immediate (same location) + %J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0] + %K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4] + %S print a possibly-shifted Rm + + %a print the address of a plain load/store + %w print the width and signedness of a core load/store + %m print register mask for ldm/stm + + %E print the lsb and width fields of a bfc/bfi instruction + %F print the lsb and width fields of a sbfx/ubfx instruction + %b print a conditional branch offset + %B print an unconditional branch offset + %s print the shift field of an SSAT instruction + %R print the rotation field of an SXT instruction + %U print barrier type. + %P print address for pli instruction. + %c print the condition code + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + + %d print bitfield in decimal + %W print bitfield*4 in decimal + %r print bitfield as an ARM register + %c print bitfield as a condition code + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + With one exception at the bottom (done because BL and BLX(1) need + to come dead last), this table was machine-sorted first in + decreasing order of number of bits set in the mask, then in + increasing numeric order of mask, then in increasing numeric order + of opcode. This order is not the clearest for a human reader, but + is guaranteed never to catch a special-case bit pattern with a more + general mask, which is important, because this instruction encoding + makes heavy use of special-case bit patterns. */ +static const struct opcode32 thumb32_opcodes[] = +{ + /* V7 instructions. */ + {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, + {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, + {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"}, + + /* Instructions defined in the basic V6T2 set. */ + {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"}, + {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"}, + {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"}, + {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"}, + {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"}, + {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"}, + + {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"}, + {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"}, + {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"}, + {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"}, + {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"}, + {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"}, + {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"}, + {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"}, + {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"}, + {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"}, + {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"}, + {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"}, + + /* Filter out Bcc with cond=E or F, which are used for other instructions. */ + {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"}, + {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"}, + {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"}, + {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"}, + + /* These have been 32-bit since the invention of Thumb. */ + {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"}, + {ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"}, + + /* Fallback. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined"}, + {0, 0, 0, 0} +}; + +static const char *const arm_conditional[] = +{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "", ""}; + +static const char *const arm_fp_const[] = +{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; + +static const char *const arm_shift[] = +{"lsl", "lsr", "asr", "ror"}; + +typedef struct +{ + const char *name; + const char *description; + const char *reg_names[16]; +} +arm_regname; + +static const arm_regname regnames[] = +{ + { "raw" , "Select raw register names", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, + { "gcc", "Select register names used by GCC", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, + { "std", "Select register names used in ARM's ISA documentation", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, + { "apcs", "Select register names used in the APCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, + { "atpcs", "Select register names used in the ATPCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, + { "special-atpcs", "Select special register names used in the ATPCS", + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, +}; + +static const char *const iwmmxt_wwnames[] = +{"b", "h", "w", "d"}; + +static const char *const iwmmxt_wwssnames[] = +{"b", "bus", "bc", "bss", + "h", "hus", "hc", "hss", + "w", "wus", "wc", "wss", + "d", "dus", "dc", "dss" +}; + +static const char *const iwmmxt_regnames[] = +{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", + "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15" +}; + +static const char *const iwmmxt_cregnames[] = +{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", + "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved" +}; + +/* Default to GCC register name set. */ +static unsigned int regname_selected = 1; + +#define NUM_ARM_REGNAMES NUM_ELEM (regnames) +#define arm_regnames regnames[regname_selected].reg_names + +static bfd_boolean force_thumb = false; + +/* Current IT instruction state. This contains the same state as the IT + bits in the CPSR. */ +static unsigned int ifthen_state; +/* IT state for the next instruction. */ +static unsigned int ifthen_next_state; +/* The address of the insn for which the IT state is valid. */ +static bfd_vma ifthen_address; +#define IFTHEN_COND ((ifthen_state >> 4) & 0xf) + +/* Cached mapping symbol state. */ +enum map_type { + MAP_ARM, + MAP_THUMB, + MAP_DATA +}; + +enum map_type last_type; +int last_mapping_sym = -1; +bfd_vma last_mapping_addr = 0; + +/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?. + Returns pointer to following character of the format string and + fills in *VALUEP and *WIDTHP with the extracted value and number of + bits extracted. WIDTHP can be NULL. */ + +static const char * +arm_decode_bitfield (const char *ptr, unsigned long insn, + unsigned long *valuep, int *widthp) +{ + unsigned long value = 0; + int width = 0; + + do + { + int start, end; + int bits; + + for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++) + start = start * 10 + *ptr - '0'; + if (*ptr == '-') + for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++) + end = end * 10 + *ptr - '0'; + else + end = start; + bits = end - start; + if (bits < 0) + abort (); + value |= ((insn >> start) & ((2ul << bits) - 1)) << width; + width += bits + 1; + } + while (*ptr++ == ','); + *valuep = value; + if (widthp) + *widthp = width; + return ptr - 1; +} + +static void +arm_decode_shift (long given, fprintf_ftype func, void *stream, + int print_shift) +{ + func (stream, "%s", arm_regnames[given & 0xf]); + + if ((given & 0xff0) != 0) + { + if ((given & 0x10) == 0) + { + int amount = (given & 0xf80) >> 7; + int shift = (given & 0x60) >> 5; + + if (amount == 0) + { + if (shift == 3) + { + func (stream, ", rrx"); + return; + } + + amount = 32; + } + + if (print_shift) + func (stream, ", %s #%d", arm_shift[shift], amount); + else + func (stream, ", #%d", amount); + } + else if (print_shift) + func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], + arm_regnames[(given & 0xf00) >> 8]); + else + func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]); + } +} + +/* Print one coprocessor instruction on INFO->STREAM. + Return true if the instuction matched, false if this is not a + recognised coprocessor instruction. */ + +static bfd_boolean +print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, + bfd_boolean thumb) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + unsigned long mask; + unsigned long value; + int cond; + + for (insn = coprocessor_opcodes; insn->assembler; insn++) + { + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt + && info->mach != bfd_mach_arm_iWMMXt2) + insn = insn + IWMMXT_INSN_COUNT; + + mask = insn->mask; + value = insn->value; + if (thumb) + { + /* The high 4 bits are 0xe for Arm conditional instructions, and + 0xe for arm unconditional instructions. The rest of the + encoding is the same. */ + mask |= 0xf0000000; + value |= 0xe0000000; + if (ifthen_state) + cond = IFTHEN_COND; + else + cond = 16; + } + else + { + /* Only match unconditional instuctions against unconditional + patterns. */ + if ((given & 0xf0000000) == 0xf0000000) + { + mask |= 0xf0000000; + cond = 16; + } + else + { + cond = (given >> 28) & 0xf; + if (cond == 0xe) + cond = 16; + } + } + if ((given & mask) == value) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'A': + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if ((given & (1 << 24)) != 0) + { + int offset = given & 0xff; + + if (offset) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "]"); + } + else + { + int offset = given & 0xff; + + func (stream, "]"); + + if (given & (1 << 21)) + { + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); + } + else + func (stream, ", {%d}", offset); + } + break; + + case 'B': + { + int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10); + int offset = (given >> 1) & 0x3f; + + if (offset == 1) + func (stream, "{d%d}", regno); + else if (regno + offset > 32) + func (stream, "{d%d-}", regno, regno + offset - 1); + else + func (stream, "{d%d-d%d}", regno, regno + offset - 1); + } + break; + + case 'C': + { + int rn = (given >> 16) & 0xf; + int offset = (given & 0xff) * 4; + int add = (given >> 23) & 1; + + func (stream, "[%s", arm_regnames[rn]); + + if (offset) + { + if (!add) + offset = -offset; + func (stream, ", #%d", offset); + } + func (stream, "]"); + if (rn == 15) + { + func (stream, "\t; "); + /* FIXME: Unsure if info->bytes_per_chunk is the + right thing to use here. */ + info->print_address_func (offset + pc + + info->bytes_per_chunk * 2, info); + } + } + break; + + case 'c': + func (stream, "%s", arm_conditional[cond]); + break; + + case 'I': + /* Print a Cirrus/DSP shift immediate. */ + /* Immediates are 7bit signed ints with bits 0..3 in + bits 0..3 of opcode and bits 4..6 in bits 5..7 + of opcode. */ + { + int imm; + + imm = (given & 0xf) | ((given & 0xe0) >> 1); + + /* Is ``imm'' a negative number? */ + if (imm & 0x40) + imm |= (-1 << 7); + + func (stream, "%d", imm); + } + + break; + + case 'F': + switch (given & 0x00408000) + { + case 0: + func (stream, "4"); + break; + case 0x8000: + func (stream, "1"); + break; + case 0x00400000: + func (stream, "2"); + break; + default: + func (stream, "3"); + } + break; + + case 'P': + switch (given & 0x00080080) + { + case 0: + func (stream, "s"); + break; + case 0x80: + func (stream, "d"); + break; + case 0x00080000: + func (stream, "e"); + break; + default: + func (stream, _("")); + break; + } + break; + case 'Q': + switch (given & 0x00408000) + { + case 0: + func (stream, "s"); + break; + case 0x8000: + func (stream, "d"); + break; + case 0x00400000: + func (stream, "e"); + break; + default: + func (stream, "p"); + break; + } + break; + case 'R': + switch (given & 0x60) + { + case 0: + break; + case 0x20: + func (stream, "p"); + break; + case 0x40: + func (stream, "m"); + break; + default: + func (stream, "z"); + break; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); + + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'k': + { + int from = (given & (1 << 7)) ? 32 : 16; + func (stream, "%ld", from - value); + } + break; + + case 'f': + if (value > 7) + func (stream, "#%s", arm_fp_const[value & 7]); + else + func (stream, "f%ld", value); + break; + + case 'w': + if (width == 2) + func (stream, "%s", iwmmxt_wwnames[value]); + else + func (stream, "%s", iwmmxt_wwssnames[value]); + break; + + case 'g': + func (stream, "%s", iwmmxt_regnames[value]); + break; + case 'G': + func (stream, "%s", iwmmxt_cregnames[value]); + break; + + case 'x': + func (stream, "0x%lx", value); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + case 'y': + case 'z': + { + int single = *c++ == 'y'; + int regno; + + switch (*c) + { + case '4': /* Sm pair */ + func (stream, "{"); + /* Fall through. */ + case '0': /* Sm, Dm */ + regno = given & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 5) & 1; + } + else + regno += ((given >> 5) & 1) << 4; + break; + + case '1': /* Sd, Dd */ + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; + + case '2': /* Sn, Dn */ + regno = (given >> 16) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 7) & 1; + } + else + regno += ((given >> 7) & 1) << 4; + break; + + case '3': /* List */ + func (stream, "{"); + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; + + default: + abort (); + } + + func (stream, "%c%d", single ? 's' : 'd', regno); + + if (*c == '3') + { + int count = given & 0xff; + + if (single == 0) + count >>= 1; + + if (--count) + { + func (stream, "-%c%d", + single ? 's' : 'd', + regno + count); + } + + func (stream, "}"); + } + else if (*c == '4') + func (stream, ", %c%d}", single ? 's' : 'd', + regno + 1); + } + break; + + case 'L': + switch (given & 0x00400100) + { + case 0x00000000: func (stream, "b"); break; + case 0x00400000: func (stream, "h"); break; + case 0x00000100: func (stream, "w"); break; + case 0x00400100: func (stream, "d"); break; + default: + break; + } + break; + + case 'Z': + { + int value; + /* given (20, 23) | given (0, 3) */ + value = ((given >> 16) & 0xf0) | (given & 0xf); + func (stream, "%d", value); + } + break; + + case 'l': + /* This is like the 'A' operator, except that if + the width field "M" is zero, then the offset is + *not* multiplied by four. */ + { + int offset = given & 0xff; + int multiplier = (given & 0x00000100) ? 4 : 1; + + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if (offset) + { + if ((given & 0x01000000) != 0) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "], #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier); + } + else + func (stream, "]"); + } + break; + + case 'r': + { + int imm4 = (given >> 4) & 0xf; + int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1); + int ubit = (given >> 23) & 1; + const char *rm = arm_regnames [given & 0xf]; + const char *rn = arm_regnames [(given >> 16) & 0xf]; + + switch (puw_bits) + { + case 1: + /* fall through */ + case 3: + func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm); + if (imm4) + func (stream, ", lsl #%d", imm4); + break; + + case 4: + /* fall through */ + case 5: + /* fall through */ + case 6: + /* fall through */ + case 7: + func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm); + if (imm4 > 0) + func (stream, ", lsl #%d", imm4); + func (stream, "]"); + if (puw_bits == 5 || puw_bits == 7) + func (stream, "!"); + break; + + default: + func (stream, "INVALID"); + } + } + break; + + case 'i': + { + long imm5; + imm5 = ((given & 0x100) >> 4) | (given & 0xf); + func (stream, "%ld", (imm5 == 0) ? 32 : imm5); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return true; + } + } + return false; +} + +static void +print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) +{ + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (((given & 0x000f0000) == 0x000f0000) + && ((given & 0x02000000) == 0)) + { + int offset = given & 0xfff; + + func (stream, "[pc"); + + if (given & 0x01000000) + { + if ((given & 0x00800000) == 0) + offset = - offset; + + /* Pre-indexed. */ + func (stream, ", #%d]", offset); + + offset += pc + 8; + + /* Cope with the possibility of write-back + being used. Probably a very dangerous thing + for the programmer to do, but who are we to + argue ? */ + if (given & 0x00200000) + func (stream, "!"); + } + else + { + /* Post indexed. */ + func (stream, "], #%d", offset); + + /* ie ignore the offset. */ + offset = pc + 8; + } + + func (stream, "\t; "); + info->print_address_func (offset, info); + } + else + { + func (stream, "[%s", + arm_regnames[(given >> 16) & 0xf]); + if ((given & 0x01000000) != 0) + { + if ((given & 0x02000000) == 0) + { + int offset = given & 0xfff; + if (offset) + func (stream, ", #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + } + else + { + func (stream, ", %s", + (((given & 0x00800000) == 0) + ? "-" : "")); + arm_decode_shift (given, func, stream, 1); + } + + func (stream, "]%s", + ((given & 0x00200000) != 0) ? "!" : ""); + } + else + { + if ((given & 0x02000000) == 0) + { + int offset = given & 0xfff; + if (offset) + func (stream, "], #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + else + func (stream, "]"); + } + else + { + func (stream, "], %s", + (((given & 0x00800000) == 0) + ? "-" : "")); + arm_decode_shift (given, func, stream, 1); + } + } + } +} + +/* Print one neon instruction on INFO->STREAM. + Return true if the instuction matched, false if this is not a + recognised neon instruction. */ + +static bfd_boolean +print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (thumb) + { + if ((given & 0xef000000) == 0xef000000) + { + /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding. */ + unsigned long bit28 = given & (1 << 28); + + given &= 0x00ffffff; + if (bit28) + given |= 0xf3000000; + else + given |= 0xf2000000; + } + else if ((given & 0xff000000) == 0xf9000000) + given ^= 0xf9000000 ^ 0xf4000000; + else + return false; + } + + for (insn = neon_opcodes; insn->assembler; insn++) + { + if ((given & insn->mask) == insn->value) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (thumb && ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'A': + { + static const unsigned char enc[16] = + { + 0x4, 0x14, /* st4 0,1 */ + 0x4, /* st1 2 */ + 0x4, /* st2 3 */ + 0x3, /* st3 4 */ + 0x13, /* st3 5 */ + 0x3, /* st1 6 */ + 0x1, /* st1 7 */ + 0x2, /* st2 8 */ + 0x12, /* st2 9 */ + 0x2, /* st1 10 */ + 0, 0, 0, 0, 0 + }; + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x3); + int type = ((given >> 8) & 0xf); + int n = enc[type] & 0xf; + int stride = (enc[type] >> 4) + 1; + int ix; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d", rd); + else + func (stream, "d%d-d%d", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", 32 << align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'B': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int idx_align = ((given >> 4) & 0xf); + int align = 0; + int size = ((given >> 10) & 0x3); + int idx = idx_align >> (size + 1); + int length = ((given >> 8) & 3) + 1; + int stride = 1; + int i; + + if (length > 1 && size > 0) + stride = (idx_align & (1 << size)) ? 2 : 1; + + switch (length) + { + case 1: + { + int amask = (1 << size) - 1; + if ((idx_align & (1 << size)) != 0) + return false; + if (size > 0) + { + if ((idx_align & amask) == amask) + align = 8 << size; + else if ((idx_align & amask) != 0) + return false; + } + } + break; + + case 2: + if (size == 2 && (idx_align & 2) != 0) + return false; + align = (idx_align & 1) ? 16 << size : 0; + break; + + case 3: + if ((size == 2 && (idx_align & 3) != 0) + || (idx_align & 1) != 0) + return false; + break; + + case 4: + if (size == 2) + { + if ((idx_align & 3) == 3) + return false; + align = (idx_align & 3) * 64; + } + else + align = (idx_align & 1) ? 32 << size : 0; + break; + + default: + abort (); + } + + func (stream, "{"); + for (i = 0; i < length; i++) + func (stream, "%sd%d[%d]", (i == 0) ? "" : ",", + rd + i * stride, idx); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'C': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x1); + int size = ((given >> 6) & 0x3); + int type = ((given >> 8) & 0x3); + int n = type + 1; + int stride = ((given >> 5) & 0x1); + int ix; + + if (stride && (n == 1)) + n++; + else + stride++; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d[]", rd); + else + func (stream, "d%d[]-d%d[]", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + { + int align = (8 * (type + 1)) << size; + if (type == 3) + align = (size > 1) ? align >> 1 : align; + if (type == 2 || (type == 0 && !size)) + func (stream, ", :", align); + else + func (stream, ", :%d", align); + } + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'D': + { + int raw_reg = (given & 0xf) | ((given >> 1) & 0x10); + int size = (given >> 20) & 3; + int reg = raw_reg & ((4 << size) - 1); + int ix = raw_reg >> size >> 2; + + func (stream, "d%d[%d]", reg, ix); + } + break; + + case 'E': + /* Neon encoded constant for mov, mvn, vorr, vbic */ + { + int bits = 0; + int cmode = (given >> 8) & 0xf; + int op = (given >> 5) & 0x1; + unsigned long value = 0, hival = 0; + unsigned shift; + int size = 0; + int isfloat = 0; + + bits |= ((given >> 24) & 1) << 7; + bits |= ((given >> 16) & 7) << 4; + bits |= ((given >> 0) & 15) << 0; + + if (cmode < 8) + { + shift = (cmode >> 1) & 3; + value = (unsigned long)bits << (8 * shift); + size = 32; + } + else if (cmode < 12) + { + shift = (cmode >> 1) & 1; + value = (unsigned long)bits << (8 * shift); + size = 16; + } + else if (cmode < 14) + { + shift = (cmode & 1) + 1; + value = (unsigned long)bits << (8 * shift); + value |= (1ul << (8 * shift)) - 1; + size = 32; + } + else if (cmode == 14) + { + if (op) + { + /* bit replication into bytes */ + int ix; + unsigned long mask; + + value = 0; + hival = 0; + for (ix = 7; ix >= 0; ix--) + { + mask = ((bits >> ix) & 1) ? 0xff : 0; + if (ix <= 3) + value = (value << 8) | mask; + else + hival = (hival << 8) | mask; + } + size = 64; + } + else + { + /* byte replication */ + value = (unsigned long)bits; + size = 8; + } + } + else if (!op) + { + /* floating point encoding */ + int tmp; + + value = (unsigned long)(bits & 0x7f) << 19; + value |= (unsigned long)(bits & 0x80) << 24; + tmp = bits & 0x40 ? 0x3c : 0x40; + value |= (unsigned long)tmp << 24; + size = 32; + isfloat = 1; + } + else + { + func (stream, "", + bits, cmode, op); + size = 32; + break; + } + switch (size) + { + case 8: + func (stream, "#%ld\t; 0x%.2lx", value, value); + break; + + case 16: + func (stream, "#%ld\t; 0x%.4lx", value, value); + break; + + case 32: + if (isfloat) + { + unsigned char valbytes[4]; + double fvalue; + + /* Do this a byte at a time so we don't have to + worry about the host's endianness. */ + valbytes[0] = value & 0xff; + valbytes[1] = (value >> 8) & 0xff; + valbytes[2] = (value >> 16) & 0xff; + valbytes[3] = (value >> 24) & 0xff; + + floatformat_to_double + (&floatformat_ieee_single_little, valbytes, + &fvalue); + + func (stream, "#%.7g\t; 0x%.8lx", fvalue, + value); + } + else + func (stream, "#%ld\t; 0x%.8lx", + (long) ((value & 0x80000000) + ? value | ~0xffffffffl : value), value); + break; + + case 64: + func (stream, "#0x%.8lx%.8lx", hival, value); + break; + + default: + abort (); + } + } + break; + + case 'F': + { + int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10); + int num = (given >> 8) & 0x3; + + if (!num) + func (stream, "{d%d}", regno); + else if (num + regno >= 32) + func (stream, "{d%d-= '0' && *c <= '9') + limit = *c - '0'; + else if (*c >= 'a' && *c <= 'f') + limit = *c - 'a' + 10; + else + abort (); + low = limit >> 2; + high = limit & 3; + + if (value < low || value > high) + func (stream, "", base << value); + else + func (stream, "%d", base << value); + } + break; + case 'R': + if (given & (1 << 6)) + goto Q; + /* FALLTHROUGH */ + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + Q: + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return true; + } + } + return false; +} + +/* Print one ARM instruction from PC on INFO->STREAM. */ + +static void +print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (print_insn_coprocessor (pc, info, given, false)) + return; + + if (print_insn_neon (info, given, false)) + return; + + for (insn = arm_opcodes; insn->assembler; insn++) + { + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt) + insn = insn + IWMMXT_INSN_COUNT; + + if ((given & insn->mask) == insn->value + /* Special case: an instruction with all bits set in the condition field + (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask, + or by the catchall at the end of the table. */ + && ((given & 0xF0000000) != 0xF0000000 + || (insn->mask & 0xF0000000) == 0xF0000000 + || (insn->mask == 0 && insn->value == 0))) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'a': + print_arm_address (pc, info, given); + break; + + case 'P': + /* Set P address bit and use normal address + printing routine. */ + print_arm_address (pc, info, given | (1 << 24)); + break; + + case 's': + if ((given & 0x004f0000) == 0x004f0000) + { + /* PC relative with immediate offset. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + + if ((given & 0x00800000) == 0) + offset = -offset; + + func (stream, "[pc, #%d]\t; ", offset); + info->print_address_func (offset + pc + 8, info); + } + else + { + func (stream, "[%s", + arm_regnames[(given >> 16) & 0xf]); + if ((given & 0x01000000) != 0) + { + /* Pre-indexed. */ + if ((given & 0x00400000) == 0x00400000) + { + /* Immediate. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + if (offset) + func (stream, ", #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + } + else + { + /* Register. */ + func (stream, ", %s%s", + (((given & 0x00800000) == 0) + ? "-" : ""), + arm_regnames[given & 0xf]); + } + + func (stream, "]%s", + ((given & 0x00200000) != 0) ? "!" : ""); + } + else + { + /* Post-indexed. */ + if ((given & 0x00400000) == 0x00400000) + { + /* Immediate. */ + int offset = ((given & 0xf00) >> 4) | (given & 0xf); + if (offset) + func (stream, "], #%s%d", + (((given & 0x00800000) == 0) + ? "-" : ""), offset); + else + func (stream, "]"); + } + else + { + /* Register. */ + func (stream, "], %s%s", + (((given & 0x00800000) == 0) + ? "-" : ""), + arm_regnames[given & 0xf]); + } + } + } + break; + + case 'b': + { + int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000); + info->print_address_func (disp*4 + pc + 8, info); + } + break; + + case 'c': + if (((given >> 28) & 0xf) != 0xe) + func (stream, "%s", + arm_conditional [(given >> 28) & 0xf]); + break; + + case 'm': + { + int started = 0; + int reg; + + func (stream, "{"); + for (reg = 0; reg < 16; reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + func (stream, "}"); + } + break; + + case 'q': + arm_decode_shift (given, func, stream, 0); + break; + + case 'o': + if ((given & 0x02000000) != 0) + { + int rotate = (given & 0xf00) >> 7; + int immed = (given & 0xff); + immed = (((immed << (32 - rotate)) + | (immed >> rotate)) & 0xffffffff); + func (stream, "#%d\t; 0x%x", immed, immed); + } + else + arm_decode_shift (given, func, stream, 1); + break; + + case 'p': + if ((given & 0x0000f000) == 0x0000f000) + func (stream, "p"); + break; + + case 't': + if ((given & 0x01200000) == 0x00200000) + func (stream, "t"); + break; + + case 'A': + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); + + if ((given & (1 << 24)) != 0) + { + int offset = given & 0xff; + + if (offset) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "]"); + } + else + { + int offset = given & 0xff; + + func (stream, "]"); + + if (given & (1 << 21)) + { + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); + } + else + func (stream, ", {%d}", offset); + } + break; + + case 'B': + /* Print ARM V5 BLX(1) address: pc+25 bits. */ + { + bfd_vma address; + bfd_vma offset = 0; + + if (given & 0x00800000) + /* Is signed, hi bits should be ones. */ + offset = (-1) ^ 0x00ffffff; + + /* Offset is (SignExtend(offset field)<<2). */ + offset += given & 0x00ffffff; + offset <<= 2; + address = offset + pc + 8; + + if (given & 0x01000000) + /* H bit allows addressing to 2-byte boundaries. */ + address += 2; + + info->print_address_func (address, info); + } + break; + + case 'C': + func (stream, "_"); + if (given & 0x80000) + func (stream, "f"); + if (given & 0x40000) + func (stream, "s"); + if (given & 0x20000) + func (stream, "x"); + if (given & 0x10000) + func (stream, "c"); + break; + + case 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); + + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'b': + func (stream, "%ld", value * 8); + break; + case 'W': + func (stream, "%ld", value + 1); + break; + case 'x': + func (stream, "0x%08lx", value); + + /* Some SWI instructions have special + meanings. */ + if ((given & 0x0fffffff) == 0x0FF00000) + func (stream, "\t; IMB"); + else if ((given & 0x0fffffff) == 0x0FF00001) + func (stream, "\t; IMBRange"); + break; + case 'X': + func (stream, "%01lx", value & 0xf); + break; + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + case 'e': + { + int imm; + + imm = (given & 0xf) | ((given & 0xfff00) >> 4); + func (stream, "%d", imm); + } + break; + + case 'E': + /* LSB and WIDTH fields of BFI or BFC. The machine- + language instruction encodes LSB and MSB. */ + { + long msb = (given & 0x001f0000) >> 16; + long lsb = (given & 0x00000f80) >> 7; + + long width = msb - lsb + 1; + if (width > 0) + func (stream, "#%lu, #%lu", lsb, width); + else + func (stream, "(invalid: %lu:%lu)", lsb, msb); + } + break; + + case 'V': + /* 16-bit unsigned immediate from a MOVT or MOVW + instruction, encoded in bits 0:11 and 15:19. */ + { + long hi = (given & 0x000f0000) >> 4; + long lo = (given & 0x00000fff); + long imm16 = hi | lo; + func (stream, "#%lu\t; 0x%lx", imm16, imm16); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return; + } + } + abort (); +} + +/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */ + +static void +print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode16 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + for (insn = thumb_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) + { + int domaskpc = 0; + int domasklr = 0; + + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'C': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + else + func (stream, "s"); + break; + + case 'I': + { + unsigned int tmp; + + ifthen_next_state = given & 0xff; + for (tmp = given << 1; tmp & 0xf; tmp <<= 1) + func (stream, ((given ^ tmp) & 0x10) ? "e" : "t"); + func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]); + } + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + break; + + case 'S': + { + long reg; + + reg = (given >> 3) & 0x7; + if (given & (1 << 6)) + reg += 8; + + func (stream, "%s", arm_regnames[reg]); + } + break; + + case 'D': + { + long reg; + + reg = given & 0x7; + if (given & (1 << 7)) + reg += 8; + + func (stream, "%s", arm_regnames[reg]); + } + break; + + case 'N': + if (given & (1 << 8)) + domasklr = 1; + /* Fall through. */ + case 'O': + if (*c == 'O' && (given & (1 << 8))) + domaskpc = 1; + /* Fall through. */ + case 'M': + { + int started = 0; + int reg; + + func (stream, "{"); + + /* It would be nice if we could spot + ranges, and generate the rS-rE format: */ + for (reg = 0; (reg < 8); reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + + if (domasklr) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, arm_regnames[14] /* "lr" */); + } + + if (domaskpc) + { + if (started) + func (stream, ", "); + func (stream, arm_regnames[15] /* "pc" */); + } + + func (stream, "}"); + } + break; + + case 'b': + /* Print ARM V6T2 CZB address: pc+4+6 bits. */ + { + bfd_vma address = (pc + 4 + + ((given & 0x00f8) >> 2) + + ((given & 0x0200) >> 3)); + info->print_address_func (address, info); + } + break; + + case 's': + /* Right shift immediate -- bits 6..10; 1-31 print + as themselves, 0 prints as 32. */ + { + long imm = (given & 0x07c0) >> 6; + if (imm == 0) + imm = 32; + func (stream, "#%ld", imm); + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int bitstart = *c++ - '0'; + int bitend = 0; + + while (*c >= '0' && *c <= '9') + bitstart = (bitstart * 10) + *c++ - '0'; + + switch (*c) + { + case '-': + { + long reg; + + c++; + while (*c >= '0' && *c <= '9') + bitend = (bitend * 10) + *c++ - '0'; + if (!bitend) + abort (); + reg = given >> bitstart; + reg &= (2 << (bitend - bitstart)) - 1; + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[reg]); + break; + + case 'd': + func (stream, "%ld", reg); + break; + + case 'H': + func (stream, "%ld", reg << 1); + break; + + case 'W': + func (stream, "%ld", reg << 2); + break; + + case 'a': + /* PC-relative address -- the bottom two + bits of the address are dropped + before the calculation. */ + info->print_address_func + (((pc + 4) & ~3) + (reg << 2), info); + break; + + case 'x': + func (stream, "0x%04lx", reg); + break; + + case 'B': + reg = ((reg ^ (1 << bitend)) - (1 << bitend)); + info->print_address_func (reg * 2 + pc + 4, info); + break; + + case 'c': + func (stream, "%s", arm_conditional [reg]); + break; + + default: + abort (); + } + } + break; + + case '\'': + c++; + if ((given & (1 << bitstart)) != 0) + func (stream, "%c", *c); + break; + + case '?': + ++c; + if ((given & (1 << bitstart)) != 0) + func (stream, "%c", *c++); + else + func (stream, "%c", *++c); + break; + + default: + abort (); + } + } + break; + + default: + abort (); + } + } + return; + } + + /* No match. */ + abort (); +} + +/* Return the name of an V7M special register. */ +static const char * +psr_name (int regno) +{ + switch (regno) + { + case 0: return "APSR"; + case 1: return "IAPSR"; + case 2: return "EAPSR"; + case 3: return "PSR"; + case 5: return "IPSR"; + case 6: return "EPSR"; + case 7: return "IEPSR"; + case 8: return "MSP"; + case 9: return "PSP"; + case 16: return "PRIMASK"; + case 17: return "BASEPRI"; + case 18: return "BASEPRI_MASK"; + case 19: return "FAULTMASK"; + case 20: return "CONTROL"; + default: return ""; + } +} + +/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */ + +static void +print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (print_insn_coprocessor (pc, info, given, true)) + return; + + if (print_insn_neon (info, given, true)) + return; + + for (insn = thumb32_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) + { + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + break; + + case 'I': + { + unsigned int imm12 = 0; + imm12 |= (given & 0x000000ffu); + imm12 |= (given & 0x00007000u) >> 4; + imm12 |= (given & 0x04000000u) >> 15; + func (stream, "#%u\t; 0x%x", imm12, imm12); + } + break; + + case 'M': + { + unsigned int bits = 0, imm, imm8, mod; + bits |= (given & 0x000000ffu); + bits |= (given & 0x00007000u) >> 4; + bits |= (given & 0x04000000u) >> 15; + imm8 = (bits & 0x0ff); + mod = (bits & 0xf00) >> 8; + switch (mod) + { + case 0: imm = imm8; break; + case 1: imm = ((imm8<<16) | imm8); break; + case 2: imm = ((imm8<<24) | (imm8 << 8)); break; + case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break; + default: + mod = (bits & 0xf80) >> 7; + imm8 = (bits & 0x07f) | 0x80; + imm = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff); + } + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'J': + { + unsigned int imm = 0; + imm |= (given & 0x000000ffu); + imm |= (given & 0x00007000u) >> 4; + imm |= (given & 0x04000000u) >> 15; + imm |= (given & 0x000f0000u) >> 4; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'K': + { + unsigned int imm = 0; + imm |= (given & 0x000f0000u) >> 16; + imm |= (given & 0x00000ff0u) >> 0; + imm |= (given & 0x0000000fu) << 12; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'S': + { + unsigned int reg = (given & 0x0000000fu); + unsigned int stp = (given & 0x00000030u) >> 4; + unsigned int imm = 0; + imm |= (given & 0x000000c0u) >> 6; + imm |= (given & 0x00007000u) >> 10; + + func (stream, "%s", arm_regnames[reg]); + switch (stp) + { + case 0: + if (imm > 0) + func (stream, ", lsl #%u", imm); + break; + + case 1: + if (imm == 0) + imm = 32; + func (stream, ", lsr #%u", imm); + break; + + case 2: + if (imm == 0) + imm = 32; + func (stream, ", asr #%u", imm); + break; + + case 3: + if (imm == 0) + func (stream, ", rrx"); + else + func (stream, ", ror #%u", imm); + } + } + break; + + case 'a': + { + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int op = (given & 0x00000f00) >> 8; + unsigned int i12 = (given & 0x00000fff); + unsigned int i8 = (given & 0x000000ff); + bfd_boolean writeback = false, postind = false; + int offset = 0; + + func (stream, "[%s", arm_regnames[Rn]); + if (U) /* 12-bit positive immediate offset */ + offset = i12; + else if (Rn == 15) /* 12-bit negative immediate offset */ + offset = -(int)i12; + else if (op == 0x0) /* shifted register offset */ + { + unsigned int Rm = (i8 & 0x0f); + unsigned int sh = (i8 & 0x30) >> 4; + func (stream, ", %s", arm_regnames[Rm]); + if (sh) + func (stream, ", lsl #%u", sh); + func (stream, "]"); + break; + } + else switch (op) + { + case 0xE: /* 8-bit positive immediate offset */ + offset = i8; + break; + + case 0xC: /* 8-bit negative immediate offset */ + offset = -i8; + break; + + case 0xF: /* 8-bit + preindex with wb */ + offset = i8; + writeback = true; + break; + + case 0xD: /* 8-bit - preindex with wb */ + offset = -i8; + writeback = true; + break; + + case 0xB: /* 8-bit + postindex */ + offset = i8; + postind = true; + break; + + case 0x9: /* 8-bit - postindex */ + offset = -i8; + postind = true; + break; + + default: + func (stream, ", ]"); + goto skip; + } + + if (postind) + func (stream, "], #%d", offset); + else + { + if (offset) + func (stream, ", #%d", offset); + func (stream, writeback ? "]!" : "]"); + } + + if (Rn == 15) + { + func (stream, "\t; "); + info->print_address_func (((pc + 4) & ~3) + offset, info); + } + } + skip: + break; + + case 'A': + { + unsigned int P = (given & 0x01000000) >> 24; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int W = (given & 0x00400000) >> 21; + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int off = (given & 0x000000ff); + + func (stream, "[%s", arm_regnames[Rn]); + if (P) + { + if (off || !U) + func (stream, ", #%c%u", U ? '+' : '-', off * 4); + func (stream, "]"); + if (W) + func (stream, "!"); + } + else + { + func (stream, "], "); + if (W) + func (stream, "#%c%u", U ? '+' : '-', off * 4); + else + func (stream, "{%u}", off); + } + } + break; + + case 'w': + { + unsigned int Sbit = (given & 0x01000000) >> 24; + unsigned int type = (given & 0x00600000) >> 21; + switch (type) + { + case 0: func (stream, Sbit ? "sb" : "b"); break; + case 1: func (stream, Sbit ? "sh" : "h"); break; + case 2: + if (Sbit) + func (stream, "??"); + break; + case 3: + func (stream, "??"); + break; + } + } + break; + + case 'm': + { + int started = 0; + int reg; + + func (stream, "{"); + for (reg = 0; reg < 16; reg++) + if ((given & (1 << reg)) != 0) + { + if (started) + func (stream, ", "); + started = 1; + func (stream, "%s", arm_regnames[reg]); + } + func (stream, "}"); + } + break; + + case 'E': + { + unsigned int msb = (given & 0x0000001f); + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, msb - lsb + 1); + } + break; + + case 'F': + { + unsigned int width = (given & 0x0000001f) + 1; + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, width); + } + break; + + case 'b': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int J1 = (given & 0x00002000u) >> 13; + unsigned int J2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 20; + offset |= J2 << 19; + offset |= J1 << 18; + offset |= (given & 0x003f0000) >> 4; + offset |= (given & 0x000007ff) << 1; + offset -= (1 << 20); + + info->print_address_func (pc + 4 + offset, info); + } + break; + + case 'B': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int I1 = (given & 0x00002000u) >> 13; + unsigned int I2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 24; + offset |= !(I1 ^ S) << 23; + offset |= !(I2 ^ S) << 22; + offset |= (given & 0x03ff0000u) >> 4; + offset |= (given & 0x000007ffu) << 1; + offset -= (1 << 24); + offset += pc + 4; + + /* BLX target addresses are always word aligned. */ + if ((given & 0x00001000u) == 0) + offset &= ~2u; + + info->print_address_func (offset, info); + } + break; + + case 's': + { + unsigned int shift = 0; + shift |= (given & 0x000000c0u) >> 6; + shift |= (given & 0x00007000u) >> 10; + if (given & 0x00200000u) + func (stream, ", asr #%u", shift); + else if (shift) + func (stream, ", lsl #%u", shift); + /* else print nothing - lsl #0 */ + } + break; + + case 'R': + { + unsigned int rot = (given & 0x00000030) >> 4; + if (rot) + func (stream, ", ror #%u", rot * 8); + } + break; + + case 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case 'C': + if ((given & 0xff) == 0) + { + func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C'); + if (given & 0x800) + func (stream, "f"); + if (given & 0x400) + func (stream, "s"); + if (given & 0x200) + func (stream, "x"); + if (given & 0x100) + func (stream, "c"); + } + else + { + func (stream, psr_name (given & 0xff)); + } + break; + + case 'D': + if ((given & 0xff) == 0) + func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); + else + func (stream, psr_name (given & 0xff)); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long val; + + c = arm_decode_bitfield (c, given, &val, &width); + + switch (*c) + { + case 'd': func (stream, "%lu", val); break; + case 'W': func (stream, "%lu", val * 4); break; + case 'r': func (stream, "%s", arm_regnames[val]); break; + + case 'c': + func (stream, "%s", arm_conditional[val]); + break; + + case '\'': + c++; + if (val == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + + case '`': + c++; + if (val == 0) + func (stream, "%c", *c); + break; + + case '?': + func (stream, "%c", c[(1 << width) - (int)val]); + c += 1 << width; + break; + + default: + abort (); + } + } + break; + + default: + abort (); + } + } + return; + } + + /* No match. */ + abort (); +} + +/* Print data bytes on INFO->STREAM. */ + +static void +print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info, + long given) +{ + switch (info->bytes_per_chunk) + { + case 1: + info->fprintf_func (info->stream, ".byte\t0x%02lx", given); + break; + case 2: + info->fprintf_func (info->stream, ".short\t0x%04lx", given); + break; + case 4: + info->fprintf_func (info->stream, ".word\t0x%08lx", given); + break; + default: + abort (); + } +} + +/* Search back through the insn stream to determine if this instruction is + conditionally executed. */ +static void +find_ifthen_state (bfd_vma pc, struct disassemble_info *info, + bfd_boolean little) +{ + unsigned char b[2]; + unsigned int insn; + int status; + /* COUNT is twice the number of instructions seen. It will be odd if we + just crossed an instruction boundary. */ + int count; + int it_count; + unsigned int seen_it; + bfd_vma addr; + + ifthen_address = pc; + ifthen_state = 0; + + addr = pc; + count = 1; + it_count = 0; + seen_it = 0; + /* Scan backwards looking for IT instructions, keeping track of where + instruction boundaries are. We don't know if something is actually an + IT instruction until we find a definite instruction boundary. */ + for (;;) + { + if (addr == 0 || info->symbol_at_address_func(addr, info)) + { + /* A symbol must be on an instruction boundary, and will not + be within an IT block. */ + if (seen_it && (count & 1)) + break; + + return; + } + addr -= 2; + status = info->read_memory_func (addr, (bfd_byte *)b, 2, info); + if (status) + return; + + if (little) + insn = (b[0]) | (b[1] << 8); + else + insn = (b[1]) | (b[0] << 8); + if (seen_it) + { + if ((insn & 0xf800) < 0xe800) + { + /* Addr + 2 is an instruction boundary. See if this matches + the expected boundary based on the position of the last + IT candidate. */ + if (count & 1) + break; + seen_it = 0; + } + } + if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0) + { + /* This could be an IT instruction. */ + seen_it = insn; + it_count = count >> 1; + } + if ((insn & 0xf800) >= 0xe800) + count++; + else + count = (count + 2) | 1; + /* IT blocks contain at most 4 instructions. */ + if (count >= 8 && !seen_it) + return; + } + /* We found an IT instruction. */ + ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f); + if ((ifthen_state & 0xf) == 0) + ifthen_state = 0; +} + +/* NOTE: There are no checks in these routines that + the relevant number of data bytes exist. */ + +int +print_insn_arm (bfd_vma pc, struct disassemble_info *info) +{ + unsigned char b[4]; + long given; + int status; + int is_thumb = false; + int is_data = false; + unsigned int size = 4; + void (*printer) (bfd_vma, struct disassemble_info *, long); +#if 0 + bfd_boolean found = false; + + if (info->disassembler_options) + { + parse_disassembler_options (info->disassembler_options); + + /* To avoid repeated parsing of these options, we remove them here. */ + info->disassembler_options = NULL; + } + + /* First check the full symtab for a mapping symbol, even if there + are no usable non-mapping symbols for this address. */ + if (info->symtab != NULL + && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour) + { + bfd_vma addr; + int n; + int last_sym = -1; + enum map_type type = MAP_ARM; + + if (pc <= last_mapping_addr) + last_mapping_sym = -1; + is_thumb = (last_type == MAP_THUMB); + found = false; + /* Start scanning at the start of the function, or wherever + we finished last time. */ + n = info->symtab_pos + 1; + if (n < last_mapping_sym) + n = last_mapping_sym; + + /* Scan up to the location being disassembled. */ + for (; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + break; + if ((info->section == NULL + || info->section == info->symtab[n]->section) + && get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = true; + } + } + + if (!found) + { + n = info->symtab_pos; + if (n < last_mapping_sym - 1) + n = last_mapping_sym - 1; + + /* No mapping symbol found at this address. Look backwards + for a preceeding one. */ + for (; n >= 0; n--) + { + if (get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = true; + break; + } + } + } + + last_mapping_sym = last_sym; + last_type = type; + is_thumb = (last_type == MAP_THUMB); + is_data = (last_type == MAP_DATA); + + /* Look a little bit ahead to see if we should print out + two or four bytes of data. If there's a symbol, + mapping or otherwise, after two bytes then don't + print more. */ + if (is_data) + { + size = 4 - (pc & 3); + for (n = last_sym + 1; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + { + if (addr - pc < size) + size = addr - pc; + break; + } + } + /* If the next symbol is after three bytes, we need to + print only part of the data, so that we can use either + .byte or .short. */ + if (size == 3) + size = (pc & 1) ? 1 : 2; + } + } + + if (info->symbols != NULL) + { + if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) + { + coff_symbol_type * cs; + + cs = coffsymbol (*info->symbols); + is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT + || cs->native->u.syment.n_sclass == C_THUMBSTAT + || cs->native->u.syment.n_sclass == C_THUMBLABEL + || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC + || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC); + } + else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour + && !found) + { + /* If no mapping symbol has been found then fall back to the type + of the function symbol. */ + elf_symbol_type * es; + unsigned int type; + + es = *(elf_symbol_type **)(info->symbols); + type = ELF_ST_TYPE (es->internal_elf_sym.st_info); + + is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); + } + } +#else + int little; + + little = (info->endian == BFD_ENDIAN_LITTLE); + is_thumb |= (pc & 1); + pc &= ~(bfd_vma)1; +#endif + + if (force_thumb) + is_thumb = true; + + info->bytes_per_line = 4; + + if (is_data) + { + int i; + + /* size was already set above. */ + info->bytes_per_chunk = size; + printer = print_insn_data; + + status = info->read_memory_func (pc, (bfd_byte *)b, size, info); + given = 0; + if (little) + for (i = size - 1; i >= 0; i--) + given = b[i] | (given << 8); + else + for (i = 0; i < (int) size; i++) + given = b[i] | (given << 8); + } + else if (!is_thumb) + { + /* In ARM mode endianness is a straightforward issue: the instruction + is four bytes long and is either ordered 0123 or 3210. */ + printer = print_insn_arm_internal; + info->bytes_per_chunk = 4; + size = 4; + + status = info->read_memory_func (pc, (bfd_byte *)b, 4, info); + if (little) + given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + else + given = (b[3]) | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); + } + else + { + /* In Thumb mode we have the additional wrinkle of two + instruction lengths. Fortunately, the bits that determine + the length of the current instruction are always to be found + in the first two bytes. */ + printer = print_insn_thumb16; + info->bytes_per_chunk = 2; + size = 2; + + status = info->read_memory_func (pc, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8); + else + given = (b[1]) | (b[0] << 8); + + if (!status) + { + /* These bit patterns signal a four-byte Thumb + instruction. */ + if ((given & 0xF800) == 0xF800 + || (given & 0xF800) == 0xF000 + || (given & 0xF800) == 0xE800) + { + status = info->read_memory_func (pc + 2, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8) | (given << 16); + else + given = (b[1]) | (b[0] << 8) | (given << 16); + + printer = print_insn_thumb32; + size = 4; + } + } + + if (ifthen_address != pc) + find_ifthen_state(pc, info, little); + + if (ifthen_state) + { + if ((ifthen_state & 0xf) == 0x8) + ifthen_next_state = 0; + else + ifthen_next_state = (ifthen_state & 0xe0) + | ((ifthen_state & 0xf) << 1); + } + } + + if (status) + { + info->memory_error_func (status, pc, info); + return -1; + } + if (info->flags & INSN_HAS_RELOC) + /* If the instruction has a reloc associated with it, then + the offset field in the instruction will actually be the + addend for the reloc. (We are using REL type relocs). + In such cases, we can ignore the pc when computing + addresses, since the addend is not currently pc-relative. */ + pc = 0; + + printer (pc, info, given); + + if (is_thumb) + { + ifthen_state = ifthen_next_state; + ifthen_address += size; + } + return size; +} diff --git a/qemu/qemu-git/arm.ld b/qemu/qemu-git/arm.ld new file mode 100644 index 0000000..12b3edb --- /dev/null +++ b/qemu/qemu-git/arm.ld @@ -0,0 +1,153 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.gen_code) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .data1 : { *(.data1) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/bswap.h b/qemu/qemu-git/bswap.h new file mode 100644 index 0000000..4558704 --- /dev/null +++ b/qemu/qemu-git/bswap.h @@ -0,0 +1,217 @@ +#ifndef BSWAP_H +#define BSWAP_H + +#include "config-host.h" + +#include + +#ifdef CONFIG_MACHINE_BSWAP_H +#include +#include +#include +#else + +#ifdef CONFIG_BYTESWAP_H +#include +#else + +#define bswap_16(x) \ +({ \ + uint16_t __x = (x); \ + ((uint16_t)( \ + (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ +}) + +#define bswap_32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +#define bswap_64(x) \ +({ \ + uint64_t __x = (x); \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ +}) + +#endif /* !CONFIG_BYTESWAP_H */ + +static inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +#endif /* ! CONFIG_MACHINE_BSWAP_H */ + +static inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(HOST_WORDS_BIGENDIAN) +#define be_bswap(v, size) (v) +#define le_bswap(v, size) bswap ## size(v) +#define be_bswaps(v, size) +#define le_bswaps(p, size) *p = bswap ## size(*p); +#else +#define le_bswap(v, size) (v) +#define be_bswap(v, size) bswap ## size(v) +#define le_bswaps(v, size) +#define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(_ARCH_PPC) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) +#define be32_to_cpupu(p) be32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v & 0xff; + p1[1] = v >> 8; +} + +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v & 0xff; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static inline uint32_t be32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24); +} + +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v & 0xff; +} + +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v & 0xff; +} + +#endif + +#ifdef HOST_WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/qemu/qemu-git/cache-utils.h b/qemu/qemu-git/cache-utils.h new file mode 100644 index 0000000..b45fde4 --- /dev/null +++ b/qemu/qemu-git/cache-utils.h @@ -0,0 +1,41 @@ +#ifndef QEMU_CACHE_UTILS_H +#define QEMU_CACHE_UTILS_H + +#if defined(_ARCH_PPC) +struct qemu_cache_conf { + unsigned long dcache_bsize; + unsigned long icache_bsize; +}; + +extern struct qemu_cache_conf qemu_cache_conf; + +extern void qemu_cache_utils_init(char **envp); + +/* mildly adjusted code from tcg-dyngen.c */ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p, start1, stop1; + unsigned long dsize = qemu_cache_conf.dcache_bsize; + unsigned long isize = qemu_cache_conf.icache_bsize; + + start1 = start & ~(dsize - 1); + stop1 = (stop + dsize - 1) & ~(dsize - 1); + for (p = start1; p < stop1; p += dsize) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + + start &= start & ~(isize - 1); + stop1 = (stop + isize - 1) & ~(isize - 1); + for (p = start1; p < stop1; p += isize) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} + +#else +#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) +#endif + +#endif /* QEMU_CACHE_UTILS_H */ diff --git a/qemu/qemu-git/config.h b/qemu/qemu-git/config.h new file mode 100644 index 0000000..e20f786 --- /dev/null +++ b/qemu/qemu-git/config.h @@ -0,0 +1,2 @@ +#include "config-host.h" +#include "config-target.h" diff --git a/qemu/qemu-git/configure-small b/qemu/qemu-git/configure-small new file mode 100755 index 0000000..2f629e4 --- /dev/null +++ b/qemu/qemu-git/configure-small @@ -0,0 +1,1094 @@ +#!/bin/sh +# +# qemu configure script (c) 2003 Fabrice Bellard +# +# set temporary file name +if test ! -z "$TMPDIR" ; then + TMPDIR1="${TMPDIR}" +elif test ! -z "$TEMPDIR" ; then + TMPDIR1="${TEMPDIR}" +else + TMPDIR1="/tmp" +fi + +TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" +TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o" +TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" + +trap "rm -f $TMPC $TMPO $TMPE ; exit" 0 2 3 15 + +compile_object() { + $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null +} + +compile_prog() { + local_cflags="$1" + local_ldflags="$2" + $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null +} + +# default parameters +cpu="" +static="no" +sparc_cpu="" +cross_prefix="" +cc="gcc" +block_drv_whitelist="" +host_cc="gcc" +ar="ar" +make="make" +ld="ld" +helper_cflags="" +libs_softmmu="" + +# parse CC options first +for opt do + optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` + case "$opt" in + --cross-prefix=*) cross_prefix="$optarg" + ;; + --cc=*) cc="$optarg" + ;; + --cpu=*) cpu="$optarg" + ;; + --extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS" + ;; + --extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS" + ;; + --sparc_cpu=*) + sparc_cpu="$optarg" + case $sparc_cpu in + v7|v8|v8plus|v8plusa) + cpu="sparc" + ;; + v9) + cpu="sparc64" + ;; + *) + echo "undefined SPARC architecture. Exiting"; + exit 1 + ;; + esac + ;; + esac +done +# OS specific +# Using uname is really, really broken. Once we have the right set of checks +# we can eliminate it's usage altogether + +cc="${cross_prefix}${cc}" +ar="${cross_prefix}${ar}" +ld="${cross_prefix}${ld}" + +# default flags for all hosts +QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" +CFLAGS="-g $CFLAGS" +QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" +QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" +QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" +QEMU_CFLAGS="-U_FORTIFY_SOURCE $QEMU_CFLAGS" +QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS" +LDFLAGS="-g $LDFLAGS" + +gcc_flags="-Wold-style-declaration -Wold-style-definition" +cat > $TMPC << EOF +int main(void) { } +EOF +for flag in $gcc_flags; do + if compile_prog "$QEMU_CFLAGS" "$flag" ; then + QEMU_CFLAGS="$flag $QEMU_CFLAGS" + fi +done + +# check that the C compiler works. +cat > $TMPC < $TMPC < /dev/null | /usr/bin/grep -v "no ar in"` + if test -z "$sol_ar" ; then + echo "Error: No path includes ar" + if test -f /usr/ccs/bin/ar ; then + echo "Add /usr/ccs/bin to your path and rerun configure" + fi + exit 1 + fi +fi + + +feature_not_found() { + feature=$1 + + echo "ERROR" + echo "ERROR: User requested feature $feature" + echo "ERROR: configure was not able to find it" + echo "ERROR" + exit 1; +} + +if test -z "$cross_prefix" ; then + +# --- +# big/little endian test +cat > $TMPC << EOF +#include +int main(int argc, char ** argv){ + volatile uint32_t i=0x01234567; + return (*((uint8_t*)(&i))) == 0x67; +} +EOF + +if compile_prog "" "" ; then +$TMPE && bigendian="yes" +else +echo big/little test failed +fi + +else + +# if cross compiling, cannot launch a program, so make a static guess +case "$cpu" in + armv4b|hppa|m68k|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + bigendian=yes + ;; +esac + +fi + +# host long bits test +hostlongbits="32" +case "$cpu" in + x86_64|alpha|ia64|sparc64|ppc64|s390x) + hostlongbits=64 + ;; +esac + + +########################################## +# zlib check + +cat > $TMPC << EOF +#include +int main(void) { zlibVersion(); return 0; } +EOF +if compile_prog "" "-lz" ; then + : +else + echo + echo "Error: zlib check failed" + echo "Make sure to have the zlib libs and headers installed." + echo + exit 1 +fi + +########################################## +# Sparse probe +if test "$sparse" != "no" ; then + if test -x "$(which cgcc 2>/dev/null)"; then + sparse=yes + else + if test "$sparse" = "yes" ; then + feature_not_found "sparse" + fi + sparse=no + fi +fi + +########################################## +# fnmatch() probe, used for ACL routines +fnmatch="no" +cat > $TMPC << EOF +#include +int main(void) +{ + fnmatch("foo", "foo", 0); + return 0; +} +EOF +if compile_prog "" "" ; then + fnmatch="yes" +fi + +########################################## +# pthread probe +PTHREADLIBS_LIST="-lpthread -lpthreadGC2" + +pthread=no +cat > $TMPC << EOF +#include +int main(void) { pthread_create(0,0,0,0); return 0; } +EOF +for pthread_lib in $PTHREADLIBS_LIST; do + if compile_prog "" "$pthread_lib" ; then + pthread=yes + LIBS="$pthread_lib $LIBS" + break + fi +done + +if test "$mingw32" != yes -a "$pthread" = no; then + echo + echo "Error: pthread check failed" + echo "Make sure to have the pthread libs and headers installed." + echo + exit 1 +fi + +########################################## +# iovec probe +cat > $TMPC < +#include +#include +int main(void) { struct iovec iov; return 0; } +EOF +iovec=no +if compile_prog "" "" ; then + iovec=yes +fi + +########################################## +# preadv probe +cat > $TMPC < +#include +#include +int main(void) { preadv; } +EOF +preadv=no +if compile_prog "" "" ; then + preadv=yes +fi + +# check if pipe2 is there +pipe2=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include +#include + +int main(void) +{ + int pipefd[2]; + pipe2(pipefd, O_CLOEXEC); + return 0; +} +EOF +if compile_prog "" "" ; then + pipe2=yes +fi + +# check if accept4 is there +accept4=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include +#include + +int main(void) +{ + accept4(0, NULL, NULL, SOCK_CLOEXEC); + return 0; +} +EOF +if compile_prog "" "" ; then + accept4=yes +fi + +# Search for bswap_32 function +byteswap_h=no +cat > $TMPC << EOF +#include +int main(void) { return bswap_32(0); } +EOF +if compile_prog "" "" ; then + byteswap_h=yes +fi + +# Search for bswap_32 function +bswap_h=no +cat > $TMPC << EOF +#include +#include +#include +int main(void) { return bswap32(0); } +EOF +if compile_prog "" "" ; then + bswap_h=yes +fi + +########################################## +# Do we need librt +cat > $TMPC < +#include +int main(void) { clockid_t id; return clock_gettime(id, NULL); } +EOF + +if compile_prog "" "" ; then + : +elif compile_prog "" "-lrt" ; then + LIBS="-lrt $LIBS" +fi + +if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ + "$aix" != "yes" ; then + libs_softmmu="-lutil $libs_softmmu" +fi + +########################################## +# check if the compiler defines offsetof + +need_offsetof=yes +cat > $TMPC << EOF +#include +int main(void) { struct s { int f; }; return offsetof(struct s, f); } +EOF +if compile_prog "" "" ; then + need_offsetof=no +fi + +########################################## +# check if the compiler understands attribute warn_unused_result +# +# This could be smarter, but gcc -Werror does not error out even when warning +# about attribute warn_unused_result + +gcc_attribute_warn_unused_result=no +cat > $TMPC << EOF +#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4) +#error gcc 3.3 or older +#endif +int main(void) { return 0;} +EOF +if compile_prog "" ""; then + gcc_attribute_warn_unused_result=yes +fi + +########################################## +# check if we have fdatasync + +fdatasync=no +cat > $TMPC << EOF +#include +int main(void) { return fdatasync(0); } +EOF +if compile_prog "" "" ; then + fdatasync=yes +fi + +# End of CC checks +# After here, no more $cc or $ld runs + +if test "$debug" = "no" ; then + CFLAGS="-O2 $CFLAGS" +fi + +# Consult white-list to determine whether to enable werror +# by default. Only enable by default for git builds +z_version=`cut -f3 -d. $source_path/VERSION` + +if test -z "$werror" ; then + if test "$z_version" = "50" -a \ + "$linux" = "yes" ; then + werror="yes" + else + werror="no" + fi +fi + +# Disable zero malloc errors for official releases unless explicitly told to +# enable/disable +if test -z "$zero_malloc" ; then + if test "$z_version" = "50" ; then + zero_malloc="no" + else + zero_malloc="yes" + fi +fi + +if test "$werror" = "yes" ; then + QEMU_CFLAGS="-Werror $QEMU_CFLAGS" +fi + +if test "$solaris" = "no" ; then + if $ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then + LDFLAGS="-Wl,--warn-common $LDFLAGS" + fi +fi + +echo "Source path $source_path" +echo "C compiler $cc" +echo "Host C compiler $host_cc" +echo "CFLAGS $CFLAGS" +echo "QEMU_CFLAGS $QEMU_CFLAGS" +echo "LDFLAGS $LDFLAGS" +echo "make $make" +echo "host CPU $cpu" +echo "host big endian $bigendian" +echo "target list arm-softmmu" +echo "tcg debug enabled $debug_tcg" +echo "gprof enabled $gprof" +echo "sparse enabled $sparse" +echo "strip binaries $strip_opt" +echo "profiler $profiler" +echo "static build $static" +echo "-Werror enabled $werror" +echo "mingw32 support $mingw32" +echo "Block whitelist $block_drv_whitelist" +if test -n "$sparc_cpu"; then + echo "Target Sparc Arch $sparc_cpu" +fi +echo "preadv support $preadv" +echo "fdatasync $fdatasync" + +config_host_mak="config-host.mak" +config_host_ld="config-host.ld" + +echo "# Automatically generated by configure - do not modify" > $config_host_mak +printf "# Configured with:" >> $config_host_mak +printf " '%s'" "$0" "$@" >> $config_host_mak +echo >> $config_host_mak + +case "$cpu" in + i386|x86_64|alpha|cris|hppa|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + ARCH=$cpu + ;; + armv4b|armv4l) + ARCH=arm + ;; + *) + echo "Unsupported CPU = $cpu" + exit 1 + ;; +esac +echo "ARCH=$ARCH" >> $config_host_mak +if test "$debug_tcg" = "yes" ; then + echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak +fi +if test "$debug" = "yes" ; then + echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak +fi +if test "$strip_opt" = "yes" ; then + echo "STRIP_OPT=-s" >> $config_host_mak +fi +if test "$bigendian" = "yes" ; then + echo "HOST_WORDS_BIGENDIAN=y" >> $config_host_mak +fi +echo "HOST_LONG_BITS=$hostlongbits" >> $config_host_mak +if test "$mingw32" = "yes" ; then + echo "CONFIG_WIN32=y" >> $config_host_mak +else + echo "CONFIG_POSIX=y" >> $config_host_mak +fi + +if test "$linux" = "yes" ; then + echo "CONFIG_LINUX=y" >> $config_host_mak +fi + +if test "$darwin" = "yes" ; then + echo "CONFIG_DARWIN=y" >> $config_host_mak +fi + +if test "$aix" = "yes" ; then + echo "CONFIG_AIX=y" >> $config_host_mak +fi + +if test "$solaris" = "yes" ; then + echo "CONFIG_SOLARIS=y" >> $config_host_mak + echo "CONFIG_SOLARIS_VERSION=$solarisrev" >> $config_host_mak + if test "$needs_libsunmath" = "yes" ; then + echo "CONFIG_NEEDS_LIBSUNMATH=y" >> $config_host_mak + fi +fi +if test "$static" = "yes" ; then + echo "CONFIG_STATIC=y" >> $config_host_mak + LDFLAGS="-static $LDFLAGS" +fi +if test $profiler = "yes" ; then + echo "CONFIG_PROFILER=y" >> $config_host_mak +fi +echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak +if test "$fnmatch" = "yes" ; then + echo "CONFIG_FNMATCH=y" >> $config_host_mak +fi +qemu_version=`head $source_path/VERSION` +echo "VERSION=$qemu_version" >>$config_host_mak +echo "PKGVERSION=$pkgversion" >>$config_host_mak +echo "SRC_PATH=$source_path" >> $config_host_mak +if test "$pipe2" = "yes" ; then + echo "CONFIG_PIPE2=y" >> $config_host_mak +fi +if test "$accept4" = "yes" ; then + echo "CONFIG_ACCEPT4=y" >> $config_host_mak +fi +if test "$byteswap_h" = "yes" ; then + echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak +fi +if test "$bswap_h" = "yes" ; then + echo "CONFIG_MACHINE_BSWAP_H=y" >> $config_host_mak +fi +if test "$iovec" = "yes" ; then + echo "CONFIG_IOVEC=y" >> $config_host_mak +fi +if test "$preadv" = "yes" ; then + echo "CONFIG_PREADV=y" >> $config_host_mak +fi +if test "$need_offsetof" = "yes" ; then + echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak +fi +if test "$gcc_attribute_warn_unused_result" = "yes" ; then + echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak +fi +if test "$fdatasync" = "yes" ; then + echo "CONFIG_FDATASYNC=y" >> $config_host_mak +fi + +# XXX: suppress that +if [ "$bsd" = "yes" ] ; then + echo "CONFIG_BSD=y" >> $config_host_mak +fi + +if test "$zero_malloc" = "yes" ; then + echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak +fi + +echo "MAKE=$make" >> $config_host_mak +echo "CC=$cc" >> $config_host_mak +echo "HOST_CC=$host_cc" >> $config_host_mak +if test "$sparse" = "yes" ; then + echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak + echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak + echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak +fi +echo "AR=$ar" >> $config_host_mak +echo "LD=$ld" >> $config_host_mak +echo "CFLAGS=$CFLAGS" >> $config_host_mak +echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak +echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak +echo "LDFLAGS=$LDFLAGS" >> $config_host_mak +echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak +echo "ARLIBS_END=$arlibs_end" >> $config_host_mak +echo "LIBS+=$LIBS" >> $config_host_mak +echo "EXESUF=$EXESUF" >> $config_host_mak + +# generate list of library paths for linker script + +$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > ${config_host_ld} + +if test -f ${config_host_ld}~ ; then + if cmp -s $config_host_ld ${config_host_ld}~ ; then + mv ${config_host_ld}~ $config_host_ld + else + rm ${config_host_ld}~ + fi +fi + +config_target_mak=arm-softmmu/config-target.mak + +mkdir -p arm-softmmu +mkdir -p arm-softmmu/fpu +mkdir -p arm-softmmu/tcg + +# +# don't use ln -sf as not all "ln -sf" over write the file/link +# +rm -f arm-softmmu/Makefile +ln -s $source_path/Makefile-small.target arm-softmmu/Makefile + + +echo "# Automatically generated by configure - do not modify" > $config_target_mak + +gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" +target_phys_bits=32 +echo "TARGET_ARCH=arm" >> $config_target_mak +echo "TARGET_ARM=y" >> $config_target_mak +echo "TARGET_BASE_ARCH=arm" >> $config_target_mak +if [ $target_phys_bits -lt $hostlongbits ] ; then + target_phys_bits=$hostlongbits +fi +echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak +echo "CONFIG_SOFTMMU=y" >> $config_target_mak +echo "LIBS+=$libs_softmmu" >> $config_target_mak +echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak +echo "subdir-arm-softmmu: subdir-libhw$target_phys_bits" >> $config_host_mak +list="" +if test ! -z "$gdb_xml_files" ; then + for x in $gdb_xml_files; do + list="$list $source_path/gdb-xml/$x" + done + echo "TARGET_XML_FILES=$list" >> $config_target_mak +fi + +echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak +#echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak + +# generate QEMU_CFLAGS/LDFLAGS for targets + +cflags="" +ldflags="" + +if test "$ARCH" = "sparc64" ; then + cflags="-I\$(SRC_PATH)/tcg/sparc $cflags" +elif test "$ARCH" = "s390x" ; then + cflags="-I\$(SRC_PATH)/tcg/s390 $cflags" +else + cflags="-I\$(SRC_PATH)/tcg/\$(ARCH) $cflags" +fi +cflags="-I\$(SRC_PATH)/tcg $cflags" +cflags="-I\$(SRC_PATH)/fpu $cflags" + +for i in $ARCH arm ; do + case "$i" in + alpha) + echo "CONFIG_ALPHA_DIS=y" >> $config_target_mak + ;; + arm) + echo "CONFIG_ARM_DIS=y" >> $config_target_mak + ;; + cris) + echo "CONFIG_CRIS_DIS=y" >> $config_target_mak + ;; + hppa) + echo "CONFIG_HPPA_DIS=y" >> $config_target_mak + ;; + i386|x86_64) + echo "CONFIG_I386_DIS=y" >> $config_target_mak + ;; + m68k) + echo "CONFIG_M68K_DIS=y" >> $config_target_mak + ;; + microblaze) + echo "CONFIG_MICROBLAZE_DIS=y" >> $config_target_mak + ;; + mips*) + echo "CONFIG_MIPS_DIS=y" >> $config_target_mak + ;; + ppc*) + echo "CONFIG_PPC_DIS=y" >> $config_target_mak + ;; + s390*) + echo "CONFIG_S390_DIS=y" >> $config_target_mak + ;; + sh4) + echo "CONFIG_SH4_DIS=y" >> $config_target_mak + ;; + sparc*) + echo "CONFIG_SPARC_DIS=y" >> $config_target_mak + ;; + esac +done + +case "$ARCH" in +alpha) + # Ensure there's only a single GP + cflags="-msmall-data $cflags" +;; +ia64) + cflags="-mno-sdata $cflags" +;; +esac + +if test "$gprof" = "yes" ; then + echo "TARGET_GPROF=yes" >> $config_target_mak + ldflags="-p $ldflags" + echo "GPROF_CFLAGS=-p" >> $config_target_mak +fi + +linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/\$(ARCH).ld" +case "$ARCH" in +ia64) + ldflags="-Wl,-G0 $linker_script -static $ldflags" + ;; +esac + +echo "LDFLAGS+=$ldflags" >> $config_target_mak +echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak + +# build tree in object directory if source path is different from current one +if test "$source_path_used" = "yes" ; then + FILES="Makefile-small" + # remove the link and recreate it, as not all "ln -sf" overwrite the link + for f in $FILES ; do + rm -f $f + ln -s $source_path/$f $f + done +fi + +for hwlib in 32 64; do + d=libhw$hwlib + mkdir -p $d + rm -f $d/Makefile + ln -s $source_path/Makefile-small.hw $d/Makefile + echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" >> $d/config.mak +done diff --git a/qemu/qemu-git/cpu-all.h b/qemu/qemu-git/cpu-all.h new file mode 100644 index 0000000..57b69f8 --- /dev/null +++ b/qemu/qemu-git/cpu-all.h @@ -0,0 +1,1076 @@ +/* + * defines common to all virtual CPUs + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_ALL_H +#define CPU_ALL_H + +#include "qemu-common.h" +#include "cpu-common.h" + +/* some important defines: + * + * WORDS_ALIGNED : if defined, the host cpu can only make word aligned + * memory accesses. + * + * HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and + * otherwise little endian. + * + * (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet)) + * + * TARGET_WORDS_BIGENDIAN : same for target cpu + */ + +#include "softfloat.h" + +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#define BSWAP_NEEDED +#endif + +#ifdef BSWAP_NEEDED + +static inline uint16_t tswap16(uint16_t s) +{ + return bswap16(s); +} + +static inline uint32_t tswap32(uint32_t s) +{ + return bswap32(s); +} + +static inline uint64_t tswap64(uint64_t s) +{ + return bswap64(s); +} + +static inline void tswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void tswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void tswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#else + +static inline uint16_t tswap16(uint16_t s) +{ + return s; +} + +static inline uint32_t tswap32(uint32_t s) +{ + return s; +} + +static inline uint64_t tswap64(uint64_t s) +{ + return s; +} + +static inline void tswap16s(uint16_t *s) +{ +} + +static inline void tswap32s(uint32_t *s) +{ +} + +static inline void tswap64s(uint64_t *s) +{ +} + +#endif + +#if TARGET_LONG_SIZE == 4 +#define tswapl(s) tswap32(s) +#define tswapls(s) tswap32s((uint32_t *)(s)) +#define bswaptls(s) bswap32s(s) +#else +#define tswapl(s) tswap64(s) +#define tswapls(s) tswap64s((uint64_t *)(s)) +#define bswaptls(s) bswap64s(s) +#endif + +typedef union { + float32 f; + uint32_t l; +} CPU_FloatU; + +/* NOTE: arm FPA is horrible as double 32 bit words are stored in big + endian ! */ +typedef union { + float64 d; +#if defined(HOST_WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upper; + uint32_t lower; + } l; +#else + struct { + uint32_t lower; + uint32_t upper; + } l; +#endif + uint64_t ll; +} CPU_DoubleU; + +#ifdef TARGET_SPARC +typedef union { + float128 q; +#if defined(HOST_WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; +#endif + +/* CPU memory access without any memory or io remapping */ + +/* + * the generic syntax for the memory accesses is: + * + * load: ld{type}{sign}{size}{endian}_{access_type}(ptr) + * + * store: st{type}{size}{endian}_{access_type}(ptr, val) + * + * type is: + * (empty): integer access + * f : float access + * + * sign is: + * (empty): for floats or 32 bit size + * u : unsigned + * s : signed + * + * size is: + * b: 8 bits + * w: 16 bits + * l: 32 bits + * q: 64 bits + * + * endian is: + * (empty): target cpu endianness or 8 bit access + * r : reversed target cpu endianness (not implemented yet) + * be : big endian (not implemented yet) + * le : little endian (not implemented yet) + * + * access_type is: + * raw : host memory access + * user : user mode access using soft MMU + * kernel : kernel mode access using soft MMU + */ +static inline int ldub_p(const void *ptr) +{ + return *(uint8_t *)ptr; +} + +static inline int ldsb_p(const void *ptr) +{ + return *(int8_t *)ptr; +} + +static inline void stb_p(void *ptr, int v) +{ + *(uint8_t *)ptr = v; +} + +/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the + kernel handles unaligned load/stores may give better results, but + it is a system wide setting : bad */ +#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) + +/* conservative code for little endian unaligned accesses */ +static inline int lduw_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + const uint8_t *p = ptr; + return p[0] | (p[1] << 8); +#endif +} + +static inline int ldsw_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; +#else + const uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline int ldl_le_p(const void *ptr) +{ +#ifdef _ARCH_PPC + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + const uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +#endif +} + +static inline uint64_t ldq_le_p(const void *ptr) +{ + const uint8_t *p = ptr; + uint32_t v1, v2; + v1 = ldl_le_p(p); + v2 = ldl_le_p(p + 4); + return v1 | ((uint64_t)v2 << 32); +} + +static inline void stw_le_p(void *ptr, int v) +{ +#ifdef _ARCH_PPC + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; +#endif +} + +static inline void stl_le_p(void *ptr, int v) +{ +#ifdef _ARCH_PPC + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +#endif +} + +static inline void stq_le_p(void *ptr, uint64_t v) +{ + uint8_t *p = ptr; + stl_le_p(p, (uint32_t)v); + stl_le_p(p + 4, v >> 32); +} + +/* float access */ + +static inline float32 ldfl_le_p(const void *ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = ldl_le_p(ptr); + return u.f; +} + +static inline void stfl_le_p(void *ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + stl_le_p(ptr, u.i); +} + +static inline float64 ldfq_le_p(const void *ptr) +{ + CPU_DoubleU u; + u.l.lower = ldl_le_p(ptr); + u.l.upper = ldl_le_p(ptr + 4); + return u.d; +} + +static inline void stfq_le_p(void *ptr, float64 v) +{ + CPU_DoubleU u; + u.d = v; + stl_le_p(ptr, u.l.lower); + stl_le_p(ptr + 4, u.l.upper); +} + +#else + +static inline int lduw_le_p(const void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw_le_p(const void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl_le_p(const void *ptr) +{ + return *(uint32_t *)ptr; +} + +static inline uint64_t ldq_le_p(const void *ptr) +{ + return *(uint64_t *)ptr; +} + +static inline void stw_le_p(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl_le_p(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +static inline void stq_le_p(void *ptr, uint64_t v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float32 ldfl_le_p(const void *ptr) +{ + return *(float32 *)ptr; +} + +static inline float64 ldfq_le_p(const void *ptr) +{ + return *(float64 *)ptr; +} + +static inline void stfl_le_p(void *ptr, float32 v) +{ + *(float32 *)ptr = v; +} + +static inline void stfq_le_p(void *ptr, float64 v) +{ + *(float64 *)ptr = v; +} +#endif + +#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) + +static inline int lduw_be_p(const void *ptr) +{ +#if defined(__i386__) + int val; + asm volatile ("movzwl %1, %0\n" + "xchgb %b0, %h0\n" + : "=q" (val) + : "m" (*(uint16_t *)ptr)); + return val; +#else + const uint8_t *b = ptr; + return ((b[0] << 8) | b[1]); +#endif +} + +static inline int ldsw_be_p(const void *ptr) +{ +#if defined(__i386__) + int val; + asm volatile ("movzwl %1, %0\n" + "xchgb %b0, %h0\n" + : "=q" (val) + : "m" (*(uint16_t *)ptr)); + return (int16_t)val; +#else + const uint8_t *b = ptr; + return (int16_t)((b[0] << 8) | b[1]); +#endif +} + +static inline int ldl_be_p(const void *ptr) +{ +#if defined(__i386__) || defined(__x86_64__) + int val; + asm volatile ("movl %1, %0\n" + "bswap %0\n" + : "=r" (val) + : "m" (*(uint32_t *)ptr)); + return val; +#else + const uint8_t *b = ptr; + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +#endif +} + +static inline uint64_t ldq_be_p(const void *ptr) +{ + uint32_t a,b; + a = ldl_be_p(ptr); + b = ldl_be_p((uint8_t *)ptr + 4); + return (((uint64_t)a<<32)|b); +} + +static inline void stw_be_p(void *ptr, int v) +{ +#if defined(__i386__) + asm volatile ("xchgb %b0, %h0\n" + "movw %w0, %1\n" + : "=q" (v) + : "m" (*(uint16_t *)ptr), "0" (v)); +#else + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 8; + d[1] = v; +#endif +} + +static inline void stl_be_p(void *ptr, int v) +{ +#if defined(__i386__) || defined(__x86_64__) + asm volatile ("bswap %0\n" + "movl %0, %1\n" + : "=r" (v) + : "m" (*(uint32_t *)ptr), "0" (v)); +#else + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +#endif +} + +static inline void stq_be_p(void *ptr, uint64_t v) +{ + stl_be_p(ptr, v >> 32); + stl_be_p((uint8_t *)ptr + 4, v); +} + +/* float access */ + +static inline float32 ldfl_be_p(const void *ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = ldl_be_p(ptr); + return u.f; +} + +static inline void stfl_be_p(void *ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + stl_be_p(ptr, u.i); +} + +static inline float64 ldfq_be_p(const void *ptr) +{ + CPU_DoubleU u; + u.l.upper = ldl_be_p(ptr); + u.l.lower = ldl_be_p((uint8_t *)ptr + 4); + return u.d; +} + +static inline void stfq_be_p(void *ptr, float64 v) +{ + CPU_DoubleU u; + u.d = v; + stl_be_p(ptr, u.l.upper); + stl_be_p((uint8_t *)ptr + 4, u.l.lower); +} + +#else + +static inline int lduw_be_p(const void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw_be_p(const void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl_be_p(const void *ptr) +{ + return *(uint32_t *)ptr; +} + +static inline uint64_t ldq_be_p(const void *ptr) +{ + return *(uint64_t *)ptr; +} + +static inline void stw_be_p(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl_be_p(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +static inline void stq_be_p(void *ptr, uint64_t v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float32 ldfl_be_p(const void *ptr) +{ + return *(float32 *)ptr; +} + +static inline float64 ldfq_be_p(const void *ptr) +{ + return *(float64 *)ptr; +} + +static inline void stfl_be_p(void *ptr, float32 v) +{ + *(float32 *)ptr = v; +} + +static inline void stfq_be_p(void *ptr, float64 v) +{ + *(float64 *)ptr = v; +} + +#endif + +/* target CPU memory access functions */ +#if defined(TARGET_WORDS_BIGENDIAN) +#define lduw_p(p) lduw_be_p(p) +#define ldsw_p(p) ldsw_be_p(p) +#define ldl_p(p) ldl_be_p(p) +#define ldq_p(p) ldq_be_p(p) +#define ldfl_p(p) ldfl_be_p(p) +#define ldfq_p(p) ldfq_be_p(p) +#define stw_p(p, v) stw_be_p(p, v) +#define stl_p(p, v) stl_be_p(p, v) +#define stq_p(p, v) stq_be_p(p, v) +#define stfl_p(p, v) stfl_be_p(p, v) +#define stfq_p(p, v) stfq_be_p(p, v) +#else +#define lduw_p(p) lduw_le_p(p) +#define ldsw_p(p) ldsw_le_p(p) +#define ldl_p(p) ldl_le_p(p) +#define ldq_p(p) ldq_le_p(p) +#define ldfl_p(p) ldfl_le_p(p) +#define ldfq_p(p) ldfq_le_p(p) +#define stw_p(p, v) stw_le_p(p, v) +#define stl_p(p, v) stl_le_p(p, v) +#define stq_p(p, v) stq_le_p(p, v) +#define stfl_p(p, v) stfl_le_p(p, v) +#define stfq_p(p, v) stfq_le_p(p, v) +#endif + +/* MMU memory access macros */ + +#if defined(CONFIG_USER_ONLY) +#include +#include "qemu-types.h" + +/* On some host systems the guest address space is reserved on the host. + * This allows the guest address space to be offset to a convenient location. + */ +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long guest_base; +extern int have_guest_base; +#define GUEST_BASE guest_base +#else +#define GUEST_BASE 0ul +#endif + +/* All direct uses of g2h and h2g need to go away for usermode softmmu. */ +#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) +#define h2g(x) ({ \ + unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \ + /* Check if given address fits target address space */ \ + assert(__ret == (abi_ulong)__ret); \ + (abi_ulong)__ret; \ +}) +#define h2g_valid(x) ({ \ + unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \ + (__guest == (abi_ulong)__guest); \ +}) + +#define saddr(x) g2h(x) +#define laddr(x) g2h(x) + +#else /* !CONFIG_USER_ONLY */ +/* NOTE: we use double casts if pointers and target_ulong have + different sizes */ +#define saddr(x) (uint8_t *)(long)(x) +#define laddr(x) (uint8_t *)(long)(x) +#endif + +#define ldub_raw(p) ldub_p(laddr((p))) +#define ldsb_raw(p) ldsb_p(laddr((p))) +#define lduw_raw(p) lduw_p(laddr((p))) +#define ldsw_raw(p) ldsw_p(laddr((p))) +#define ldl_raw(p) ldl_p(laddr((p))) +#define ldq_raw(p) ldq_p(laddr((p))) +#define ldfl_raw(p) ldfl_p(laddr((p))) +#define ldfq_raw(p) ldfq_p(laddr((p))) +#define stb_raw(p, v) stb_p(saddr((p)), v) +#define stw_raw(p, v) stw_p(saddr((p)), v) +#define stl_raw(p, v) stl_p(saddr((p)), v) +#define stq_raw(p, v) stq_p(saddr((p)), v) +#define stfl_raw(p, v) stfl_p(saddr((p)), v) +#define stfq_raw(p, v) stfq_p(saddr((p)), v) + + +#if defined(CONFIG_USER_ONLY) + +/* if user mode, no other memory access functions */ +#define ldub(p) ldub_raw(p) +#define ldsb(p) ldsb_raw(p) +#define lduw(p) lduw_raw(p) +#define ldsw(p) ldsw_raw(p) +#define ldl(p) ldl_raw(p) +#define ldq(p) ldq_raw(p) +#define ldfl(p) ldfl_raw(p) +#define ldfq(p) ldfq_raw(p) +#define stb(p, v) stb_raw(p, v) +#define stw(p, v) stw_raw(p, v) +#define stl(p, v) stl_raw(p, v) +#define stq(p, v) stq_raw(p, v) +#define stfl(p, v) stfl_raw(p, v) +#define stfq(p, v) stfq_raw(p, v) + +#define ldub_code(p) ldub_raw(p) +#define ldsb_code(p) ldsb_raw(p) +#define lduw_code(p) lduw_raw(p) +#define ldsw_code(p) ldsw_raw(p) +#define ldl_code(p) ldl_raw(p) +#define ldq_code(p) ldq_raw(p) + +#define ldub_kernel(p) ldub_raw(p) +#define ldsb_kernel(p) ldsb_raw(p) +#define lduw_kernel(p) lduw_raw(p) +#define ldsw_kernel(p) ldsw_raw(p) +#define ldl_kernel(p) ldl_raw(p) +#define ldq_kernel(p) ldq_raw(p) +#define ldfl_kernel(p) ldfl_raw(p) +#define ldfq_kernel(p) ldfq_raw(p) +#define stb_kernel(p, v) stb_raw(p, v) +#define stw_kernel(p, v) stw_raw(p, v) +#define stl_kernel(p, v) stl_raw(p, v) +#define stq_kernel(p, v) stq_raw(p, v) +#define stfl_kernel(p, v) stfl_raw(p, v) +#define stfq_kernel(p, vt) stfq_raw(p, v) + +#endif /* defined(CONFIG_USER_ONLY) */ + +/* page related stuff */ + +#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) +#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) +#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) + +/* ??? These should be the larger of unsigned long and target_ulong. */ +extern unsigned long qemu_real_host_page_size; +extern unsigned long qemu_host_page_bits; +extern unsigned long qemu_host_page_size; +extern unsigned long qemu_host_page_mask; + +#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask) + +/* same as PROT_xxx */ +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 +/* original state of the write flag (used when tracking self-modifying + code */ +#define PAGE_WRITE_ORG 0x0010 +#define PAGE_RESERVED 0x0020 + +void page_dump(FILE *f); +int walk_memory_regions(void *, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)); +int page_get_flags(target_ulong address); +void page_set_flags(target_ulong start, target_ulong end, int flags); +int page_check_range(target_ulong start, target_ulong len, int flags); + +void cpu_exec_init_all(unsigned long tb_size); +CPUState *cpu_copy(CPUState *env); +CPUState *qemu_get_cpu(int cpu); + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); +void cpu_dump_statistics (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); + +void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern CPUState *first_cpu; +extern CPUState *cpu_single_env; +extern int64_t qemu_icount; +extern int use_icount; + +#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ +#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ +#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ +#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ +#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ +#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ +#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ +#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ +#define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ +#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ +#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */ + +void cpu_interrupt(CPUState *s, int mask); +void cpu_reset_interrupt(CPUState *env, int mask); + +void cpu_exit(CPUState *s); + +int qemu_cpu_has_work(CPUState *env); + +/* Breakpoint/watchpoint flags */ +#define BP_MEM_READ 0x01 +#define BP_MEM_WRITE 0x02 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) +#define BP_STOP_BEFORE_ACCESS 0x04 +#define BP_WATCHPOINT_HIT 0x08 +#define BP_GDB 0x10 +#define BP_CPU 0x20 + +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint); +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags); +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint); +void cpu_breakpoint_remove_all(CPUState *env, int mask); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint); +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, + target_ulong len, int flags); +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint); +void cpu_watchpoint_remove_all(CPUState *env, int mask); + +#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */ +#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */ +#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */ + +void cpu_single_step(CPUState *env, int enabled); +void cpu_reset(CPUState *s); + +/* Return the physical page corresponding to a virtual one. Use it + only for debugging because no protection checks are done. Return -1 + if no page found. */ +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); + +#define CPU_LOG_TB_OUT_ASM (1 << 0) +#define CPU_LOG_TB_IN_ASM (1 << 1) +#define CPU_LOG_TB_OP (1 << 2) +#define CPU_LOG_TB_OP_OPT (1 << 3) +#define CPU_LOG_INT (1 << 4) +#define CPU_LOG_EXEC (1 << 5) +#define CPU_LOG_PCALL (1 << 6) +#define CPU_LOG_IOPORT (1 << 7) +#define CPU_LOG_TB_CPU (1 << 8) +#define CPU_LOG_RESET (1 << 9) + +/* define log items */ +typedef struct CPULogItem { + int mask; + const char *name; + const char *help; +} CPULogItem; + +extern const CPULogItem cpu_log_items[]; + +void cpu_set_log(int log_flags); +void cpu_set_log_filename(const char *filename); +int cpu_str_to_log_mask(const char *str); + +/* IO ports API */ +#include "ioport.h" + +/* memory API */ + +extern int phys_ram_fd; +extern uint8_t *phys_ram_dirty; +extern ram_addr_t ram_size; +extern ram_addr_t last_ram_offset; + +/* physical memory access */ + +/* MMIO pages are identified by a combination of an IO device index and + 3 flags. The ROMD code stores the page ram offset in iotlb entry, + so only a limited number of ids are avaiable. */ + +#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) + +/* Flags stored in the low bits of the TLB virtual address. These are + defined so that fast path ram access is all zeros. */ +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << 3) +/* Set if TLB entry references a clean RAM page. The iotlb entry will + contain the page physical address. */ +#define TLB_NOTDIRTY (1 << 4) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << 5) + +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); + +#define VGA_DIRTY_FLAG 0x01 +#define CODE_DIRTY_FLAG 0x02 +#define MIGRATION_DIRTY_FLAG 0x08 + +/* read dirty bit (return 0 or 1) */ +static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; +} + +static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, + int dirty_flags) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; +} + +static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) +{ + phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; +} + +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags); +void cpu_tlb_update_dirty(CPUState *env); + +int cpu_physical_memory_set_dirty_tracking(int enable); + +int cpu_physical_memory_get_dirty_tracking(void); + +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +/* Coalesced MMIO regions are areas where write operations can be reordered. + * This usually implies that write operations are side-effect free. This allows + * batching which can make a major impact on performance when using + * virtualization. + */ +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); + +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); + +/*******************************************/ +/* host CPU ticks (if available) */ + +#if defined(_ARCH_PPC) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t retval; +#ifdef _ARCH_PPC64 + /* This reads timebase in one 64bit go and includes Cell workaround from: + http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html + */ + __asm__ __volatile__ ( + "mftb %0\n\t" + "cmpwi %0,0\n\t" + "beq- $-8" + : "=r" (retval)); +#else + /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */ + unsigned long junk; + __asm__ __volatile__ ( + "mftbu %1\n\t" + "mftb %L0\n\t" + "mftbu %0\n\t" + "cmpw %0,%1\n\t" + "bne $-16" + : "=r" (retval), "=r" (junk)); +#endif + return retval; +} + +#elif defined(__i386__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} + +#elif defined(__x86_64__) + +static inline int64_t cpu_get_real_ticks(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} + +#elif defined(__hppa__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int val; + asm volatile ("mfctl %%cr16, %0" : "=r"(val)); + return val; +} + +#elif defined(__ia64) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); + return val; +} + +#elif defined(__s390__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); + return val; +} + +#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + +static inline int64_t cpu_get_real_ticks (void) +{ +#if defined(_LP64) + uint64_t rval; + asm volatile("rd %%tick,%0" : "=r"(rval)); + return rval; +#else + union { + uint64_t i64; + struct { + uint32_t high; + uint32_t low; + } i32; + } rval; + asm volatile("rd %%tick,%1; srlx %1,32,%0" + : "=r"(rval.i32.high), "=r"(rval.i32.low)); + return rval.i64; +#endif +} + +#elif defined(__mips__) && \ + ((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)) +/* + * binutils wants to use rdhwr only on mips32r2 + * but as linux kernel emulate it, it's fine + * to use it. + * + */ +#define MIPS_RDHWR(rd, value) { \ + __asm__ __volatile__ ( \ + ".set push\n\t" \ + ".set mips32r2\n\t" \ + "rdhwr %0, "rd"\n\t" \ + ".set pop" \ + : "=r" (value)); \ +} + +static inline int64_t cpu_get_real_ticks(void) +{ +/* On kernels >= 2.6.25 rdhwr , $2 and $3 are emulated */ + uint32_t count; + static uint32_t cyc_per_count = 0; + + if (!cyc_per_count) + MIPS_RDHWR("$3", cyc_per_count); + + MIPS_RDHWR("$2", count); + return (int64_t)(count * cyc_per_count); +} + +#else +/* The host CPU doesn't have an easily accessible cycle counter. + Just return a monotonically increasing value. This will be + totally wrong, but hopefully better than nothing. */ +static inline int64_t cpu_get_real_ticks (void) +{ + static int64_t ticks = 0; + return ticks++; +} +#endif + +/* profiling */ +#ifdef CONFIG_PROFILER +static inline int64_t profile_getclock(void) +{ + return cpu_get_real_ticks(); +} + +extern int64_t qemu_time, qemu_time_start; +extern int64_t tlb_flush_time; +extern int64_t dev_time; +#endif + +void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, + uint64_t mcg_status, uint64_t addr, uint64_t misc); + +#endif /* CPU_ALL_H */ diff --git a/qemu/qemu-git/cpu-common.h b/qemu/qemu-git/cpu-common.h new file mode 100644 index 0000000..6302372 --- /dev/null +++ b/qemu/qemu-git/cpu-common.h @@ -0,0 +1,90 @@ +#ifndef CPU_COMMON_H +#define CPU_COMMON_H 1 + +/* CPU interfaces that are target indpendent. */ + +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) +#define WORDS_ALIGNED +#endif + +#include "bswap.h" + +/* address in the RAM (different from a physical address) */ +typedef unsigned long ram_addr_t; + +/* memory API */ + +typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); + +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset, + ram_addr_t region_offset); +static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0); +} + +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr); +ram_addr_t qemu_ram_alloc(ram_addr_t); +void qemu_ram_free(ram_addr_t addr); +/* This should only be used for ram local to a device. */ +void *qemu_get_ram_ptr(ram_addr_t addr); +/* This should not be used by devices. */ +ram_addr_t qemu_ram_addr_from_host(void *ptr); + +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque); +void cpu_unregister_io_memory(int table_address); + +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write); +static inline void cpu_physical_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, buf, len, 0); +} +static inline void cpu_physical_memory_write(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); +} +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write); +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len); +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); +void cpu_unregister_map_client(void *cookie); + +uint32_t ldub_phys(target_phys_addr_t addr); +uint32_t lduw_phys(target_phys_addr_t addr); +uint32_t ldl_phys(target_phys_addr_t addr); +uint64_t ldq_phys(target_phys_addr_t addr); +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); +void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val); +void stb_phys(target_phys_addr_t addr, uint32_t val); +void stw_phys(target_phys_addr_t addr, uint32_t val); +void stl_phys(target_phys_addr_t addr, uint32_t val); +void stq_phys(target_phys_addr_t addr, uint64_t val); + +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len); + +#define IO_MEM_SHIFT 3 + +#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) +#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT) + +/* Acts like a ROM when read and like a device when written. */ +#define IO_MEM_ROMD (1) +#define IO_MEM_SUBPAGE (2) +#define IO_MEM_SUBWIDTH (4) + +#endif /* !CPU_COMMON_H */ diff --git a/qemu/qemu-git/cpu-defs.h b/qemu/qemu-git/cpu-defs.h new file mode 100644 index 0000000..95068b5 --- /dev/null +++ b/qemu/qemu-git/cpu-defs.h @@ -0,0 +1,202 @@ +/* + * common defines for all CPUs + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_DEFS_H +#define CPU_DEFS_H + +#ifndef NEED_CPU_H +#error cpu.h included from common code +#endif + +#include "config.h" +#include +#include +#include +#include "osdep.h" +#include "qemu-queue.h" +#include "targphys.h" + +#ifndef TARGET_LONG_BITS +#error TARGET_LONG_BITS must be defined before including this header +#endif + +#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) + +/* target_ulong is the type of a virtual address */ +#if TARGET_LONG_SIZE == 4 +typedef int32_t target_long; +typedef uint32_t target_ulong; +#define TARGET_FMT_lx "%08x" +#define TARGET_FMT_ld "%d" +#define TARGET_FMT_lu "%u" +#elif TARGET_LONG_SIZE == 8 +typedef int64_t target_long; +typedef uint64_t target_ulong; +#define TARGET_FMT_lx "%016" PRIx64 +#define TARGET_FMT_ld "%" PRId64 +#define TARGET_FMT_lu "%" PRIu64 +#else +#error TARGET_LONG_SIZE undefined +#endif + +#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) + +#define EXCP_INTERRUPT 0x10000 /* async interruption */ +#define EXCP_HLT 0x10001 /* hlt instruction reached */ +#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ +#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ + +#define TB_JMP_CACHE_BITS 12 +#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) + +/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for + addresses on the same page. The top bits are the same. This allows + TLB invalidation to quickly clear a subset of the hash table. */ +#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2) +#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS) +#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1) +#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE) + +#define CPU_TLB_BITS 8 +#define CPU_TLB_SIZE (1 << CPU_TLB_BITS) + +#if TARGET_PHYS_ADDR_BITS == 32 && TARGET_LONG_BITS == 32 +#define CPU_TLB_ENTRY_BITS 4 +#else +#define CPU_TLB_ENTRY_BITS 5 +#endif + +typedef struct CPUTLBEntry { + /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address + bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not + go directly to ram. + bit 3 : indicates that the entry is invalid + bit 2..0 : zero + */ + target_ulong addr_read; + target_ulong addr_write; + target_ulong addr_code; + /* Addend to virtual address to get physical address. IO accesses + use the corresponding iotlb value. */ +#if TARGET_PHYS_ADDR_BITS == 64 + /* on i386 Linux make sure it is aligned */ + target_phys_addr_t addend __attribute__((aligned(8))); +#else + target_phys_addr_t addend; +#endif + /* padding to get a power of two size */ + uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) - + (sizeof(target_ulong) * 3 + + ((-sizeof(target_ulong) * 3) & (sizeof(target_phys_addr_t) - 1)) + + sizeof(target_phys_addr_t))]; +} CPUTLBEntry; + +#ifdef HOST_WORDS_BIGENDIAN +typedef struct icount_decr_u16 { + uint16_t high; + uint16_t low; +} icount_decr_u16; +#else +typedef struct icount_decr_u16 { + uint16_t low; + uint16_t high; +} icount_decr_u16; +#endif + +struct kvm_run; +struct KVMState; + +typedef struct CPUBreakpoint { + target_ulong pc; + int flags; /* BP_* */ + QTAILQ_ENTRY(CPUBreakpoint) entry; +} CPUBreakpoint; + +typedef struct CPUWatchpoint { + target_ulong vaddr; + target_ulong len_mask; + int flags; /* BP_* */ + QTAILQ_ENTRY(CPUWatchpoint) entry; +} CPUWatchpoint; + +#define CPU_TEMP_BUF_NLONGS 128 +#define CPU_COMMON \ + struct TranslationBlock *current_tb; /* currently executing TB */ \ + /* soft mmu support */ \ + /* in order to avoid passing too many arguments to the MMIO \ + helpers, we store some rarely used information in the CPU \ + context) */ \ + unsigned long mem_io_pc; /* host pc at which the memory was \ + accessed */ \ + target_ulong mem_io_vaddr; /* target virtual addr at which the \ + memory was accessed */ \ + uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ + uint32_t stop; /* Stop request */ \ + uint32_t stopped; /* Artificially stopped */ \ + uint32_t interrupt_request; \ + volatile sig_atomic_t exit_request; \ + /* The meaning of the MMU modes is defined in the target code. */ \ + CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ + target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \ + struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ + /* buffer for temporaries in the code generator */ \ + long temp_buf[CPU_TEMP_BUF_NLONGS]; \ + \ + int64_t icount_extra; /* Instructions until next timer event. */ \ + /* Number of cycles left, with interrupt flag in high bit. \ + This allows a single read-compare-cbranch-write sequence to test \ + for both decrementer underflow and exceptions. */ \ + union { \ + uint32_t u32; \ + icount_decr_u16 u16; \ + } icount_decr; \ + uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \ + \ + /* from this point: preserved by CPU reset */ \ + /* ice debug support */ \ + QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \ + int singlestep_enabled; \ + \ + QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \ + CPUWatchpoint *watchpoint_hit; \ + \ + struct GDBRegisterState *gdb_regs; \ + \ + /* Core interrupt code */ \ + jmp_buf jmp_env; \ + int exception_index; \ + \ + CPUState *next_cpu; /* next CPU sharing TB cache */ \ + int cpu_index; /* CPU index (informative) */ \ + uint32_t host_tid; /* host thread ID */ \ + int numa_node; /* NUMA node this cpu is belonging to */ \ + int nr_cores; /* number of cores within this CPU package */ \ + int nr_threads;/* number of threads within this CPU */ \ + int running; /* Nonzero if cpu is currently running(usermode). */ \ + /* user data */ \ + void *opaque; \ + \ + uint32_t created; \ + struct QemuThread *thread; \ + struct QemuCond *halt_cond; \ + const char *cpu_model_str; \ + struct KVMState *kvm_state; \ + struct kvm_run *kvm_run; \ + int kvm_fd; + +#endif diff --git a/qemu/qemu-git/cpu-exec.c b/qemu/qemu-git/cpu-exec.c new file mode 100644 index 0000000..4635be3 --- /dev/null +++ b/qemu/qemu-git/cpu-exec.c @@ -0,0 +1,1201 @@ +/* + * i386 emulator main execution loop + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#include "exec.h" +#include "disas.h" +#include "tcg.h" +#include "kvm.h" + +#if !defined(CONFIG_SOFTMMU) +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#include +#ifdef __linux__ +#include +#endif +#endif + +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +// Work around ugly bugs in glibc that mangle global register contents +#undef env +#define env cpu_single_env +#endif + +int tb_invalidated_flag; + +//#define CONFIG_DEBUG_EXEC +//#define DEBUG_SIGNAL + +int qemu_cpu_has_work(CPUState *env) +{ + return cpu_has_work(env); +} + +void cpu_loop_exit(void) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ + regs_to_env(); + longjmp(env->jmp_env, 1); +} + +/* exit the current TB from a signal handler. The host registers are + restored in a state compatible with the CPU emulator + */ +void cpu_resume_from_signal(CPUState *env1, void *puc) +{ +#if !defined(CONFIG_SOFTMMU) +#ifdef __linux__ + struct ucontext *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#endif +#endif + + env = env1; + + /* XXX: restore cpu registers saved in host registers */ + +#if !defined(CONFIG_SOFTMMU) + if (puc) { + /* XXX: use siglongjmp ? */ +#ifdef __linux__ + sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); +#elif defined(__OpenBSD__) + sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); +#endif + } +#endif + env->exception_index = -1; + longjmp(env->jmp_env, 1); +} + +/* Execute the code without caching the generated code. An interpreter + could be used if available. */ +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +{ + unsigned long next_tb; + TranslationBlock *tb; + + /* Should never happen. + We only end up here when an existing TB is too long. */ + if (max_cycles > CF_COUNT_MASK) + max_cycles = CF_COUNT_MASK; + + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, + max_cycles); + env->current_tb = tb; + /* execute the generated code */ + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + + if ((next_tb & 3) == 2) { + /* Restore PC. This may happen if async event occurs before + the TB starts executing. */ + cpu_pc_from_tb(env, tb); + } + tb_phys_invalidate(tb, -1); + tb_free(tb); +} + +static TranslationBlock *tb_find_slow(target_ulong pc, + target_ulong cs_base, + uint64_t flags) +{ + TranslationBlock *tb, **ptb1; + unsigned int h; + target_ulong phys_pc, phys_page1, phys_page2, virt_page2; + + tb_invalidated_flag = 0; + + regs_to_env(); /* XXX: do it just before cpu_gen_code() */ + + /* find translated block using physical mappings */ + phys_pc = get_phys_addr_code(env, pc); + phys_page1 = phys_pc & TARGET_PAGE_MASK; + phys_page2 = -1; + h = tb_phys_hash_func(phys_pc); + ptb1 = &tb_phys_hash[h]; + for(;;) { + tb = *ptb1; + if (!tb) + goto not_found; + if (tb->pc == pc && + tb->page_addr[0] == phys_page1 && + tb->cs_base == cs_base && + tb->flags == flags) { + /* check next page if needed */ + if (tb->page_addr[1] != -1) { + virt_page2 = (pc & TARGET_PAGE_MASK) + + TARGET_PAGE_SIZE; + phys_page2 = get_phys_addr_code(env, virt_page2); + if (tb->page_addr[1] == phys_page2) + goto found; + } else { + goto found; + } + } + ptb1 = &tb->phys_hash_next; + } + not_found: + /* if no translated code available, then translate it now */ + tb = tb_gen_code(env, pc, cs_base, flags, 0); + + found: + /* we add the TB in the virtual pc hash table */ + env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; + return tb; +} + +static inline TranslationBlock *tb_find_fast(void) +{ + TranslationBlock *tb; + target_ulong cs_base, pc; + int flags; + + /* we record a subset of the CPU state. It will + always be the same before a given translated block + is executed. */ + cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); + tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; + if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || + tb->flags != flags)) { + tb = tb_find_slow(pc, cs_base, flags); + } + return tb; +} + +static CPUDebugExcpHandler *debug_excp_handler; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) +{ + CPUDebugExcpHandler *old_handler = debug_excp_handler; + + debug_excp_handler = handler; + return old_handler; +} + +static void cpu_handle_debug_exception(CPUState *env) +{ + CPUWatchpoint *wp; + + if (!env->watchpoint_hit) + QTAILQ_FOREACH(wp, &env->watchpoints, entry) + wp->flags &= ~BP_WATCHPOINT_HIT; + + if (debug_excp_handler) + debug_excp_handler(env); +} + +/* main execution loop */ + +int cpu_exec(CPUState *env1) +{ +#define DECLARE_HOST_REGS 1 +#include "hostregs_helper.h" + int ret, interrupt_request; + TranslationBlock *tb; + uint8_t *tc_ptr; + unsigned long next_tb; + + if (cpu_halted(env1) == EXCP_HALTED) + return EXCP_HALTED; + + cpu_single_env = env1; + + /* first we save global registers */ +#define SAVE_HOST_REGS 1 +#include "hostregs_helper.h" + env = env1; + + env_to_regs(); +#if defined(TARGET_I386) + /* put eflags in CPU temporary format */ + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_SPARC) +#elif defined(TARGET_M68K) + env->cc_op = CC_OP_FLAGS; + env->cc_dest = env->sr & 0xf; + env->cc_x = (env->sr >> 4) & 1; +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_ARM) +#elif defined(TARGET_PPC) +#elif defined(TARGET_MICROBLAZE) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) +#elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) + /* XXXXX */ +#else +#error unsupported target CPU +#endif + env->exception_index = -1; + + /* prepare setjmp context for exception handling */ + for(;;) { + if (setjmp(env->jmp_env) == 0) { +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + env->current_tb = NULL; + /* if an exception is pending, we execute it here */ + if (env->exception_index >= 0) { + if (env->exception_index >= EXCP_INTERRUPT) { + /* exit request from the cpu execution loop */ + ret = env->exception_index; + if (ret == EXCP_DEBUG) + cpu_handle_debug_exception(env); + break; + } else { +#if defined(CONFIG_USER_ONLY) + /* if user mode only, we simulate a fake exception + which will be handled outside the cpu execution + loop */ +#if defined(TARGET_I386) + do_interrupt_user(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; +#endif + ret = env->exception_index; + break; +#else +#if defined(TARGET_I386) + /* simulate a real cpu exception. On i386, it can + trigger new exceptions, but we do not handle + double or triple faults yet. */ + do_interrupt(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; +#elif defined(TARGET_PPC) + do_interrupt(env); +#elif defined(TARGET_MICROBLAZE) + do_interrupt(env); +#elif defined(TARGET_MIPS) + do_interrupt(env); +#elif defined(TARGET_SPARC) + do_interrupt(env); +#elif defined(TARGET_ARM) + do_interrupt(env); +#elif defined(TARGET_SH4) + do_interrupt(env); +#elif defined(TARGET_ALPHA) + do_interrupt(env); +#elif defined(TARGET_CRIS) + do_interrupt(env); +#elif defined(TARGET_M68K) + do_interrupt(0); +#endif +#endif + } + env->exception_index = -1; + } + + if (kvm_enabled()) { + kvm_cpu_exec(env); + longjmp(env->jmp_env, 1); + } + + next_tb = 0; /* force lookup of first TB */ + for(;;) { + interrupt_request = env->interrupt_request; + if (unlikely(interrupt_request)) { + if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) { + /* Mask out external interrupts for this step. */ + interrupt_request &= ~(CPU_INTERRUPT_HARD | + CPU_INTERRUPT_FIQ | + CPU_INTERRUPT_SMI | + CPU_INTERRUPT_NMI); + } + if (interrupt_request & CPU_INTERRUPT_DEBUG) { + env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); + } +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ + defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ + defined(TARGET_MICROBLAZE) + if (interrupt_request & CPU_INTERRUPT_HALT) { + env->interrupt_request &= ~CPU_INTERRUPT_HALT; + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } +#endif +#if defined(TARGET_I386) + if (interrupt_request & CPU_INTERRUPT_INIT) { + svm_check_intercept(SVM_EXIT_INIT); + do_cpu_init(env); + env->exception_index = EXCP_HALTED; + cpu_loop_exit(); + } else if (interrupt_request & CPU_INTERRUPT_SIPI) { + do_cpu_sipi(env); + } else if (env->hflags2 & HF2_GIF_MASK) { + if ((interrupt_request & CPU_INTERRUPT_SMI) && + !(env->hflags & HF_SMM_MASK)) { + svm_check_intercept(SVM_EXIT_SMI); + env->interrupt_request &= ~CPU_INTERRUPT_SMI; + do_smm_enter(); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_NMI) && + !(env->hflags2 & HF2_NMI_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_NMI; + env->hflags2 |= HF2_NMI_MASK; + do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + next_tb = 0; + } else if (interrupt_request & CPU_INTERRUPT_MCE) { + env->interrupt_request &= ~CPU_INTERRUPT_MCE; + do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); + next_tb = 0; + } else if ((interrupt_request & CPU_INTERRUPT_HARD) && + (((env->hflags2 & HF2_VINTR_MASK) && + (env->hflags2 & HF2_HIF_MASK)) || + (!(env->hflags2 & HF2_VINTR_MASK) && + (env->eflags & IF_MASK && + !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { + int intno; + svm_check_intercept(SVM_EXIT_INTR); + env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); + intno = cpu_get_pic_interrupt(env); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + do_interrupt(intno, 0, 0, 0, 1); + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; +#if !defined(CONFIG_USER_ONLY) + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { + int intno; + /* FIXME: this should respect TPR */ + svm_check_intercept(SVM_EXIT_VINTR); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno); + do_interrupt(intno, 0, 0, 0, 1); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + next_tb = 0; +#endif + } + } +#elif defined(TARGET_PPC) +#if 0 + if ((interrupt_request & CPU_INTERRUPT_RESET)) { + cpu_reset(env); + } +#endif + if (interrupt_request & CPU_INTERRUPT_HARD) { + ppc_hw_interrupt(env); + if (env->pending_interrupts == 0) + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + next_tb = 0; + } +#elif defined(TARGET_MICROBLAZE) + if ((interrupt_request & CPU_INTERRUPT_HARD) + && (env->sregs[SR_MSR] & MSR_IE) + && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) + && !(env->iflags & (D_FLAG | IMM_FLAG))) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_MIPS) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && + (env->CP0_Status & (1 << CP0St_IE)) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + /* Raise it */ + env->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_SPARC) + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && + env->interrupt_index > 0) { + int pil = env->interrupt_index & 0xf; + int type = env->interrupt_index & 0xf0; + + if (((type == TT_EXTINT) && + cpu_pil_allowed(env, pil)) || + type != TT_EXTINT) { + env->exception_index = env->interrupt_index; + do_interrupt(env); + next_tb = 0; + } + } + } else if (interrupt_request & CPU_INTERRUPT_TIMER) { + //do_interrupt(0, 0, 0, 0, 0); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + } +#elif defined(TARGET_ARM) + if (interrupt_request & CPU_INTERRUPT_FIQ + && !(env->uncached_cpsr & CPSR_F)) { + env->exception_index = EXCP_FIQ; + do_interrupt(env); + next_tb = 0; + } + /* ARMv7-M interrupt return works by loading a magic value + into the PC. On real hardware the load causes the + return to occur. The qemu implementation performs the + jump normally, then does the exception return when the + CPU tries to execute code at the magic address. + This will cause the magic PC value to be pushed to + the stack if an interrupt occured at the wrong time. + We avoid this by disabling interrupts when + pc contains a magic address. */ + if (interrupt_request & CPU_INTERRUPT_HARD + && ((IS_M(env) && env->regs[15] < 0xfffffff0) + || !(env->uncached_cpsr & CPSR_I))) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_SH4) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_ALPHA) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_CRIS) + if (interrupt_request & CPU_INTERRUPT_HARD + && (env->pregs[PR_CCS] & I_FLAG)) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } + if (interrupt_request & CPU_INTERRUPT_NMI + && (env->pregs[PR_CCS] & M_FLAG)) { + env->exception_index = EXCP_NMI; + do_interrupt(env); + next_tb = 0; + } +#elif defined(TARGET_M68K) + if (interrupt_request & CPU_INTERRUPT_HARD + && ((env->sr & SR_I) >> SR_I_SHIFT) + < env->pending_level) { + /* Real hardware gets the interrupt vector via an + IACK cycle at this point. Current emulated + hardware doesn't rely on this, so we + provide/save the vector when the interrupt is + first signalled. */ + env->exception_index = env->pending_vector; + do_interrupt(1); + next_tb = 0; + } +#endif + /* Don't use the cached interupt_request value, + do_interrupt may have updated the EXITTB flag. */ + if (env->interrupt_request & CPU_INTERRUPT_EXITTB) { + env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + /* ensure that no TB jump will be modified as + the program flow was changed */ + next_tb = 0; + } + } + if (unlikely(env->exit_request)) { + env->exit_request = 0; + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); + } +#ifdef CONFIG_DEBUG_EXEC + if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { + /* restore flags in standard format */ + regs_to_env(); +#if defined(TARGET_I386) + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); + log_cpu_state(env, X86_DUMP_CCOP); + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_ARM) + log_cpu_state(env, 0); +#elif defined(TARGET_SPARC) + log_cpu_state(env, 0); +#elif defined(TARGET_PPC) + log_cpu_state(env, 0); +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); + log_cpu_state(env, 0); +#elif defined(TARGET_MICROBLAZE) + log_cpu_state(env, 0); +#elif defined(TARGET_MIPS) + log_cpu_state(env, 0); +#elif defined(TARGET_SH4) + log_cpu_state(env, 0); +#elif defined(TARGET_ALPHA) + log_cpu_state(env, 0); +#elif defined(TARGET_CRIS) + log_cpu_state(env, 0); +#else +#error unsupported target CPU +#endif + } +#endif + spin_lock(&tb_lock); + tb = tb_find_fast(); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ + if (tb_invalidated_flag) { + /* as some TB could have been invalidated because + of memory exceptions while generating the code, we + must recompute the hash index here */ + next_tb = 0; + tb_invalidated_flag = 0; + } +#ifdef CONFIG_DEBUG_EXEC + qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", + (long)tb->tc_ptr, tb->pc, + lookup_symbol(tb->pc)); +#endif + /* see if we can patch the calling TB. When the TB + spans two pages, we cannot safely do a direct + jump. */ + { + if (next_tb != 0 && tb->page_addr[1] == -1) { + tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); + } + } + spin_unlock(&tb_lock); + env->current_tb = tb; + + /* cpu_interrupt might be called while translating the + TB, but before it is linked into a potentially + infinite loop and becomes env->current_tb. Avoid + starting execution if there is a pending interrupt. */ + if (unlikely (env->exit_request)) + env->current_tb = NULL; + + while (env->current_tb) { + tc_ptr = tb->tc_ptr; + /* execute the generated code */ +#if defined(__sparc__) && !defined(CONFIG_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif + next_tb = tcg_qemu_tb_exec(tc_ptr); + env->current_tb = NULL; + if ((next_tb & 3) == 2) { + /* Instruction counter expired. */ + int insns_left; + tb = (TranslationBlock *)(long)(next_tb & ~3); + /* Restore PC. */ + cpu_pc_from_tb(env, tb); + insns_left = env->icount_decr.u32; + if (env->icount_extra && insns_left >= 0) { + /* Refill decrementer and continue execution. */ + env->icount_extra += insns_left; + if (env->icount_extra > 0xffff) { + insns_left = 0xffff; + } else { + insns_left = env->icount_extra; + } + env->icount_extra -= insns_left; + env->icount_decr.u16.low = insns_left; + } else { + if (insns_left > 0) { + /* Execute remaining instructions. */ + cpu_exec_nocache(insns_left, tb); + } + env->exception_index = EXCP_INTERRUPT; + next_tb = 0; + cpu_loop_exit(); + } + } + } + /* reset soft MMU for next block (it can currently + only be set by a memory fault) */ + } /* for(;;) */ + } else { + env_to_regs(); + } + } /* for(;;) */ + + +#if defined(TARGET_I386) + /* restore flags in standard format */ + env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); +#elif defined(TARGET_ARM) + /* XXX: Save/restore host fpu exception state?. */ +#elif defined(TARGET_SPARC) +#elif defined(TARGET_PPC) +#elif defined(TARGET_M68K) + cpu_m68k_flush_flags(env, env->cc_op); + env->cc_op = CC_OP_FLAGS; + env->sr = (env->sr & 0xffe0) + | env->cc_dest | (env->cc_x << 4); +#elif defined(TARGET_MICROBLAZE) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) +#elif defined(TARGET_ALPHA) +#elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) + /* XXXXX */ +#else +#error unsupported target CPU +#endif + + /* restore global registers */ +#include "hostregs_helper.h" + + /* fail safe : never use cpu_single_env outside cpu_exec() */ + cpu_single_env = NULL; + return ret; +} + +/* must only be called from the generated code as an exception can be + generated */ +void tb_invalidate_page_range(target_ulong start, target_ulong end) +{ + /* XXX: cannot enable it yet because it yields to MMU exception + where NIP != read address on PowerPC */ +#if 0 + target_ulong phys_addr; + phys_addr = get_phys_addr_code(env, start); + tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0); +#endif +} + +#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY) + +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (selector << 4), 0xffff, 0); + } else { + helper_load_seg(seg_reg, selector); + } + env = saved_env; +} + +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_fsave(ptr, data32); + + env = saved_env; +} + +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_frstor(ptr, data32); + + env = saved_env; +} + +#endif /* TARGET_I386 */ + +#if !defined(CONFIG_SOFTMMU) + +#if defined(TARGET_I386) +#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code) +#else +#define EXCEPTION_ACTION cpu_loop_exit() +#endif + +/* 'pc' is the host PC at which the exception was raised. 'address' is + the effective address of the memory exception. 'is_write' is 1 if a + write caused the exception and otherwise 0'. 'old_set' is the + signal set which should be restored */ +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set, + void *puc) +{ + TranslationBlock *tb; + int ret; + + if (cpu_single_env) + env = cpu_single_env; /* XXX: find a correct solution for multithread */ +#if defined(DEBUG_SIGNAL) + qemu_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(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); + if (ret < 0) + return 0; /* not an MMU fault */ + if (ret == 0) + return 1; /* the MMU fault was handled without causing real CPU fault */ + /* 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, puc); + } + + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + EXCEPTION_ACTION; + + /* never comes here */ + return 1; +} + +#if defined(__i386__) + +#if defined(__APPLE__) +# include + +# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) +# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) +# define ERROR_sig(context) ((context)->uc_mcontext->es.err) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined (__NetBSD__) +# include + +# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP]) +# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined (__FreeBSD__) || defined(__DragonFly__) +# include + +# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip)) +# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +# define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +# define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +# define EIP_sig(context) ((context)->sc_eip) +# define TRAP_sig(context) ((context)->sc_trapno) +# define ERROR_sig(context) ((context)->sc_err) +# define MASK_sig(context) ((context)->sc_mask) +#else +# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +# define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + unsigned long pc; + int trapno; + +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#define REG_ERR ERR +#define REG_TRAPNO TRAPNO +#endif + pc = EIP_sig(uc); + trapno = TRAP_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + trapno == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(__x86_64__) + +#ifdef __NetBSD__ +#define PC_sig(context) _UC_MACHINE_PC(context) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#elif defined(__OpenBSD__) +#define PC_sig(context) ((context)->sc_rip) +#define TRAP_sig(context) ((context)->sc_trapno) +#define ERROR_sig(context) ((context)->sc_err) +#define MASK_sig(context) ((context)->sc_mask) +#elif defined (__FreeBSD__) || defined(__DragonFly__) +#include + +#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip)) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) +#else +#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#define MASK_sig(context) ((context)->uc_sigmask) +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + unsigned long pc; +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__) + ucontext_t *uc = puc; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; +#else + struct ucontext *uc = puc; +#endif + + pc = PC_sig(uc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + TRAP_sig(uc) == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &MASK_sig(uc), puc); +} + +#elif defined(_ARCH_PPC) + +/*********************************************************************** + * signal context platform-specific definitions + * From Wine + */ +#ifdef linux +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name) +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) +# define IAR_sig(context) REG_sig(nip, context) /* Program counter */ +# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) /* Count register */ +# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */ +# define LR_sig(context) REG_sig(link, context) /* Link register */ +# define CR_sig(context) REG_sig(ccr, context) /* Condition register */ +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num]) +# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4))) +/* Exception Registers access */ +# define DAR_sig(context) REG_sig(dar, context) +# define DSISR_sig(context) REG_sig(dsisr, context) +# define TRAP_sig(context) REG_sig(trap, context) +#endif /* linux */ + +#ifdef __APPLE__ +# include +typedef struct ucontext SIGCONTEXT; +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name) +# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name) +# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name) +# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name) +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) +# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */ +# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) +# define XER_sig(context) REG_sig(xer, context) /* Link register */ +# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */ +# define CR_sig(context) REG_sig(cr, context) /* Condition register */ +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context) +# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context)) +/* Exception Registers access */ +# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */ +# define DSISR_sig(context) EXCEPREG_sig(dsisr, context) +# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ +#endif /* __APPLE__ */ + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = IAR_sig(uc); + is_write = 0; +#if 0 + /* ppc 4xx case */ + if (DSISR_sig(uc) & 0x00800000) + is_write = 1; +#else + if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) + is_write = 1; +#endif + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__alpha__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + uint32_t *pc = uc->uc_mcontext.sc_pc; + uint32_t insn = *pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster */ + switch (insn >> 26) { + case 0x0d: // stw + case 0x0e: // stb + case 0x0f: // stq_u + case 0x24: // stf + case 0x25: // stg + case 0x26: // sts + case 0x27: // stt + case 0x2c: // stl + case 0x2d: // stq + case 0x2e: // stl_c + case 0x2f: // stq_c + is_write = 1; + } + + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} +#elif defined(__sparc__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + int is_write; + uint32_t insn; +#if !defined(__arch64__) || defined(CONFIG_SOLARIS) + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); + /* XXX: is there a standard glibc define ? */ + unsigned long pc = regs[1]; +#else +#ifdef __linux__ + struct sigcontext *sc = puc; + unsigned long pc = sc->sigc_regs.tpc; + void *sigmask = (void *)sc->sigc_mask; +#elif defined(__OpenBSD__) + struct sigcontext *uc = puc; + unsigned long pc = uc->sc_pc; + void *sigmask = (void *)(long)uc->sc_mask; +#endif +#endif + + /* XXX: need kernel patch to get write flag faster */ + is_write = 0; + insn = *(uint32_t *)pc; + if ((insn >> 30) == 3) { + switch((insn >> 19) & 0x3f) { + case 0x05: // stb + case 0x15: // stba + case 0x06: // sth + case 0x16: // stha + case 0x04: // st + case 0x14: // sta + case 0x07: // std + case 0x17: // stda + case 0x0e: // stx + case 0x1e: // stxa + case 0x24: // stf + case 0x34: // stfa + case 0x27: // stdf + case 0x37: // stdfa + case 0x26: // stqf + case 0x36: // stqfa + case 0x25: // stfsr + case 0x3c: // casa + case 0x3e: // casxa + is_write = 1; + break; + } + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, sigmask, NULL); +} + +#elif defined(__arm__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + +#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) + pc = uc->uc_mcontext.gregs[R15]; +#else + pc = uc->uc_mcontext.arm_pc; +#endif + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__mc68000) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.gregs[16]; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__ia64) + +#ifndef __ISR_VALID + /* This ought to be in ... */ +# define __ISR_VALID 1 +#endif + +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long ip; + int is_write = 0; + + ip = uc->uc_mcontext.sc_ip; + switch (host_signum) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + if (info->si_code && (info->si_segvflags & __ISR_VALID)) + /* ISR.W (write-access) is bit 33: */ + is_write = (info->si_isr >> 33) & 1; + break; + + default: + break; + } + return handle_cpu_signal(ip, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__s390__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.psw.addr; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__mips__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + greg_t pc = uc->uc_mcontext.pc; + int is_write; + + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__hppa__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + struct siginfo *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.sc_iaoq[0]; + /* FIXME: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#else + +#error host CPU specific signal handler needed + +#endif + +#endif /* !defined(CONFIG_SOFTMMU) */ diff --git a/qemu/qemu-git/create_config b/qemu/qemu-git/create_config new file mode 100755 index 0000000..2f052ae --- /dev/null +++ b/qemu/qemu-git/create_config @@ -0,0 +1,99 @@ +#!/bin/sh + +echo "/* Automatically generated by create_config - do not modify */" + +while read line; do + +case $line in + VERSION=*) # configuration + version=${line#*=} + echo "#define QEMU_VERSION \"$version\"" + ;; + PKGVERSION=*) # configuration + pkgversion=${line#*=} + echo "#define QEMU_PKGVERSION \"$pkgversion\"" + ;; + ARCH=*) # configuration + arch=${line#*=} + arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'` + echo "#define HOST_$arch_name 1" + ;; + CONFIG_AUDIO_DRIVERS=*) + drivers=${line#*=} + echo "#define CONFIG_AUDIO_DRIVERS \\" + for drv in $drivers; do + echo " &${drv}_audio_driver,\\" + done + echo "" + ;; + CONFIG_BDRV_WHITELIST=*) + echo "#define CONFIG_BDRV_WHITELIST \\" + for drv in ${line#*=}; do + echo " \"${drv}\",\\" + done + echo " NULL" + ;; + CONFIG_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + CONFIG_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; + ARCH=*) # configuration + arch=${line#*=} + arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'` + echo "#define HOST_$arch_name 1" + ;; + HOST_USB=*) + # do nothing + ;; + HOST_CC=*) + # do nothing + ;; + HOST_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + HOST_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; + TARGET_ARCH=*) # configuration + target_arch=${line#*=} + echo "#define TARGET_ARCH \"$target_arch\"" + ;; + TARGET_BASE_ARCH=*) # configuration + target_base_arch=${line#*=} + if [ "$target_base_arch" != "$target_arch" ]; then + base_arch_name=`echo $target_base_arch | tr '[:lower:]' '[:upper:]'` + echo "#define TARGET_$base_arch_name 1" + fi + ;; + TARGET_XML_FILES=*) + # do nothing + ;; + TARGET_ABI_DIR=*) + # do nothing + ;; + TARGET_ARCH2=*) + # do nothing + ;; + TARGET_DIRS=*) + # do nothing + ;; + TARGET_*=y) # configuration + name=${line%=*} + echo "#define $name 1" + ;; + TARGET_*=*) # configuration + name=${line%=*} + value=${line#*=} + echo "#define $name $value" + ;; +esac + +done # read diff --git a/qemu/qemu-git/cris-dis.c b/qemu/qemu-git/cris-dis.c new file mode 100644 index 0000000..455ba8a --- /dev/null +++ b/qemu/qemu-git/cris-dis.c @@ -0,0 +1,2890 @@ +/* Disassembler code for CRIS. + Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Written by Hans-Peter Nilsson. + + This file is part of the GNU binutils and GDB, the GNU debugger. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "dis-asm.h" +//#include "sysdep.h" +#include "target-cris/opcode-cris.h" +//#include "libiberty.h" + + +void *qemu_malloc(size_t len); /* can't include qemu-common.h here */ + +#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) + +/* cris-opc.c -- Table of opcodes for the CRIS processor. + Copyright 2000, 2001, 2004 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Originally written for GAS 1.38.1 by Mikael Asker. + Reorganized by Hans-Peter Nilsson. + +This file is part of GAS, GDB and the GNU binutils. + +GAS, GDB, and GNU binutils is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, or (at your +option) any later version. + +GAS, GDB, and GNU binutils are distributed in the hope that they will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#ifndef NULL +#define NULL (0) +#endif + +/* This table isn't used for CRISv32 and the size of immediate operands. */ +const struct cris_spec_reg +cris_spec_regs[] = +{ + {"bz", 0, 1, cris_ver_v32p, NULL}, + {"p0", 0, 1, 0, NULL}, + {"vr", 1, 1, 0, NULL}, + {"p1", 1, 1, 0, NULL}, + {"pid", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_warning, NULL}, + {"srs", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_warning, NULL}, + {"wz", 4, 2, cris_ver_v32p, NULL}, + {"p4", 4, 2, 0, NULL}, + {"ccr", 5, 2, cris_ver_v0_10, NULL}, + {"exs", 5, 4, cris_ver_v32p, NULL}, + {"p5", 5, 2, cris_ver_v0_10, NULL}, + {"p5", 5, 4, cris_ver_v32p, NULL}, + {"dcr0",6, 2, cris_ver_v0_3, NULL}, + {"eda", 6, 4, cris_ver_v32p, NULL}, + {"p6", 6, 2, cris_ver_v0_3, NULL}, + {"p6", 6, 4, cris_ver_v32p, NULL}, + {"dcr1/mof", 7, 4, cris_ver_v10p, + "Register `dcr1/mof' with ambiguous size specified. Guessing 4 bytes"}, + {"dcr1/mof", 7, 2, cris_ver_v0_3, + "Register `dcr1/mof' with ambiguous size specified. Guessing 2 bytes"}, + {"mof", 7, 4, cris_ver_v10p, NULL}, + {"dcr1",7, 2, cris_ver_v0_3, NULL}, + {"p7", 7, 4, cris_ver_v10p, NULL}, + {"p7", 7, 2, cris_ver_v0_3, NULL}, + {"dz", 8, 4, cris_ver_v32p, NULL}, + {"p8", 8, 4, 0, NULL}, + {"ibr", 9, 4, cris_ver_v0_10, NULL}, + {"ebp", 9, 4, cris_ver_v32p, NULL}, + {"p9", 9, 4, 0, NULL}, + {"irp", 10, 4, cris_ver_v0_10, NULL}, + {"erp", 10, 4, cris_ver_v32p, NULL}, + {"p10", 10, 4, 0, NULL}, + {"srp", 11, 4, 0, NULL}, + {"p11", 11, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"bar/dtp0", 12, 4, cris_ver_warning, + "Ambiguous register `bar/dtp0' specified"}, + {"nrp", 12, 4, cris_ver_v32p, NULL}, + {"bar", 12, 4, cris_ver_v8_10, NULL}, + {"dtp0",12, 4, cris_ver_v0_3, NULL}, + {"p12", 12, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"dccr/dtp1",13, 4, cris_ver_warning, + "Ambiguous register `dccr/dtp1' specified"}, + {"ccs", 13, 4, cris_ver_v32p, NULL}, + {"dccr",13, 4, cris_ver_v8_10, NULL}, + {"dtp1",13, 4, cris_ver_v0_3, NULL}, + {"p13", 13, 4, 0, NULL}, + {"brp", 14, 4, cris_ver_v3_10, NULL}, + {"usp", 14, 4, cris_ver_v32p, NULL}, + {"p14", 14, 4, cris_ver_v3p, NULL}, + {"usp", 15, 4, cris_ver_v10, NULL}, + {"spc", 15, 4, cris_ver_v32p, NULL}, + {"p15", 15, 4, cris_ver_v10p, NULL}, + {NULL, 0, 0, cris_ver_version_all, NULL} +}; + +/* Add version specifiers to this table when necessary. + The (now) regular coding of register names suggests a simpler + implementation. */ +const struct cris_support_reg cris_support_regs[] = +{ + {"s0", 0}, + {"s1", 1}, + {"s2", 2}, + {"s3", 3}, + {"s4", 4}, + {"s5", 5}, + {"s6", 6}, + {"s7", 7}, + {"s8", 8}, + {"s9", 9}, + {"s10", 10}, + {"s11", 11}, + {"s12", 12}, + {"s13", 13}, + {"s14", 14}, + {"s15", 15}, + {NULL, 0} +}; + +/* All CRIS opcodes are 16 bits. + + - The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + - The args component is a string containing characters symbolically + matching the operands of an instruction. Used for both assembly + and disassembly. + + Operand-matching characters: + [ ] , space + Verbatim. + A The string "ACR" (case-insensitive). + B Not really an operand. It causes a "BDAP -size,SP" prefix to be + output for the PUSH alias-instructions and recognizes a push- + prefix at disassembly. This letter isn't recognized for v32. + Must be followed by a R or P letter. + ! Non-match pattern, will not match if there's a prefix insn. + b Non-matching operand, used for branches with 16-bit + displacement. Only recognized by the disassembler. + c 5-bit unsigned immediate in bits <4:0>. + C 4-bit unsigned immediate in bits <3:0>. + d At assembly, optionally (as in put other cases before this one) + ".d" or ".D" at the start of the operands, followed by one space + character. At disassembly, nothing. + D General register in bits <15:12> and <3:0>. + f List of flags in bits <15:12> and <3:0>. + i 6-bit signed immediate in bits <5:0>. + I 6-bit unsigned immediate in bits <5:0>. + M Size modifier (B, W or D) for CLEAR instructions. + m Size modifier (B, W or D) in bits <5:4> + N A 32-bit dword, like in the difference between s and y. + This has no effect on bits in the opcode. Can also be expressed + as "[pc+]" in input. + n As N, but PC-relative (to the start of the instruction). + o [-128..127] word offset in bits <7:1> and <0>. Used by 8-bit + branch instructions. + O [-128..127] offset in bits <7:0>. Also matches a comma and a + general register after the expression, in bits <15:12>. Used + only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode). + P Special register in bits <15:12>. + p Indicates that the insn is a prefix insn. Must be first + character. + Q As O, but don't relax; force an 8-bit offset. + R General register in bits <15:12>. + r General register in bits <3:0>. + S Source operand in bit <10> and a prefix; a 3-operand prefix + without side-effect. + s Source operand in bits <10> and <3:0>, optionally with a + side-effect prefix, except [pc] (the name, not R15 as in ACR) + isn't allowed for v32 and higher. + T Support register in bits <15:12>. + u 4-bit (PC-relative) unsigned immediate word offset in bits <3:0>. + U Relaxes to either u or n, instruction is assumed LAPCQ or LAPC. + Not recognized at disassembly. + x Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>. + y Like 's' but do not allow an integer at assembly. + Y The difference s-y; only an integer is allowed. + z Size modifier (B or W) in bit <4>. */ + + +/* Please note the order of the opcodes in this table is significant. + The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler might not recognize + them, or may indicate an internal error. + + The disassembler should not normally care about the order of the + opcodes, but will prefer an earlier alternative if the "match-score" + (see cris-dis.c) is computed as equal. + + It should not be significant for proper execution that this table is + in alphabetical order, but please follow that convention for an easy + overview. */ + +const struct cris_opcode +cris_opcodes[] = +{ + {"abs", 0x06B0, 0x0940, "r,R", 0, SIZE_NONE, 0, + cris_abs_op}, + + {"add", 0x0600, 0x09c0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0a00, 0x05c0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, + cris_ver_v32p, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addc", 0x0570, 0x0A80, "r,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addc", 0x09A0, 0x0250, "s,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addi", 0x0540, 0x0A80, "x,r,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"addi", 0x0500, 0x0Ac0, "x,r", 0, SIZE_NONE, 0, + cris_addi_op}, + + /* This collates after "addo", but we want to disassemble as "addoq", + not "addo". */ + {"addoq", 0x0100, 0x0E00, "Q,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addo", 0x0940, 0x0280, "m s,R,A", 0, SIZE_FIELD_SIGNED, + cris_ver_v32p, + cris_not_implemented_op}, + + /* This must be located after the insn above, lest we misinterpret + "addo.b -1,r0,acr" as "addo .b-1,r0,acr". FIXME: Sounds like a + parser bug. */ + {"addo", 0x0100, 0x0E00, "O,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addq", 0x0200, 0x0Dc0, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"adds", 0x0420, 0x0Bc0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"adds", 0x0820, 0x03c0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x03c0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x07c0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"addu", 0x0400, 0x0be0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"addu", 0x0800, 0x03e0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x03e0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x07e0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"and", 0x0700, 0x08C0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x04C0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"andq", 0x0300, 0x0CC0, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"asr", 0x0780, 0x0840, "m r,R", 0, SIZE_NONE, 0, + cris_asr_op}, + + {"asrq", 0x03a0, 0x0c40, "c,R", 0, SIZE_NONE, 0, + cris_asrq_op}, + + {"ax", 0x15B0, 0xEA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + /* FIXME: Should use branch #defines. */ + {"b", 0x0dff, 0x0200, "b", 1, SIZE_NONE, 0, + cris_sixteen_bit_offset_branch_op}, + + {"ba", + BA_QUICK_OPCODE, + 0x0F00+(0xF-CC_A)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* Needs to come after the usual "ba o", which might be relaxed to + this one. */ + {"ba", BA_DWORD_OPCODE, + 0xffff & (~BA_DWORD_OPCODE), "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bas", 0x0EBF, 0x0140, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"basc", 0x0EFF, 0x0100, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bcc", + BRANCH_QUICK_OPCODE+CC_CC*0x1000, + 0x0f00+(0xF-CC_CC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bcs", + BRANCH_QUICK_OPCODE+CC_CS*0x1000, + 0x0f00+(0xF-CC_CS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bdap", + BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS, "pm s,R", 0, SIZE_FIELD_SIGNED, + cris_ver_v0_10, + cris_bdap_prefix}, + + {"bdap", + BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS, "pO", 0, SIZE_NONE, + cris_ver_v0_10, + cris_quick_mode_bdap_prefix}, + + {"beq", + BRANCH_QUICK_OPCODE+CC_EQ*0x1000, + 0x0f00+(0xF-CC_EQ)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* This is deliberately put before "bext" to trump it, even though not + in alphabetical order, since we don't do excluding version checks + for v0..v10. */ + {"bwf", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v10, + cris_eight_bit_offset_branch_op}, + + {"bext", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v0_3, + cris_eight_bit_offset_branch_op}, + + {"bge", + BRANCH_QUICK_OPCODE+CC_GE*0x1000, + 0x0f00+(0xF-CC_GE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bgt", + BRANCH_QUICK_OPCODE+CC_GT*0x1000, + 0x0f00+(0xF-CC_GT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhi", + BRANCH_QUICK_OPCODE+CC_HI*0x1000, + 0x0f00+(0xF-CC_HI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhs", + BRANCH_QUICK_OPCODE+CC_HS*0x1000, + 0x0f00+(0xF-CC_HS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"biap", BIAP_OPCODE, BIAP_Z_BITS, "pm r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_biap_prefix}, + + {"ble", + BRANCH_QUICK_OPCODE+CC_LE*0x1000, + 0x0f00+(0xF-CC_LE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blo", + BRANCH_QUICK_OPCODE+CC_LO*0x1000, + 0x0f00+(0xF-CC_LO)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bls", + BRANCH_QUICK_OPCODE+CC_LS*0x1000, + 0x0f00+(0xF-CC_LS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blt", + BRANCH_QUICK_OPCODE+CC_LT*0x1000, + 0x0f00+(0xF-CC_LT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmi", + BRANCH_QUICK_OPCODE+CC_MI*0x1000, + 0x0f00+(0xF-CC_MI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmod", 0x0ab0, 0x0140, "s,R", 0, SIZE_FIX_32, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0140, "S,D", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0540, "S,R,r", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bne", + BRANCH_QUICK_OPCODE+CC_NE*0x1000, + 0x0f00+(0xF-CC_NE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bound", 0x05c0, 0x0A00, "m r,R", 0, SIZE_NONE, 0, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x09c0, 0x0200, "m s,R", 0, SIZE_FIELD, + cris_ver_v0_10, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x0dcf, 0x0200, "m Y,R", 0, SIZE_FIELD, 0, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0200, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0600, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_bound_op}, + + {"bpl", + BRANCH_QUICK_OPCODE+CC_PL*0x1000, + 0x0f00+(0xF-CC_PL)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"break", 0xe930, 0x16c0, "C", 0, SIZE_NONE, + cris_ver_v3p, + cris_break_op}, + + {"bsb", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v32p, + cris_eight_bit_offset_branch_op}, + + {"bsr", 0xBEBF, 0x4140, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bsrc", 0xBEFF, 0x4100, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bstore", 0x0af0, 0x0100, "s,R", 0, SIZE_FIX_32, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0100, "S,D", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0500, "S,R,r", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"btst", 0x04F0, 0x0B00, "r,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + {"btstq", 0x0380, 0x0C60, "c,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + + {"bvc", + BRANCH_QUICK_OPCODE+CC_VC*0x1000, + 0x0f00+(0xF-CC_VC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bvs", + BRANCH_QUICK_OPCODE+CC_VS*0x1000, + 0x0f00+(0xF-CC_VS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"clear", 0x0670, 0x3980, "M r", 0, SIZE_NONE, 0, + cris_reg_mode_clear_op}, + + {"clear", 0x0A70, 0x3180, "M y", 0, SIZE_NONE, 0, + cris_none_reg_mode_clear_test_op}, + + {"clear", 0x0A70, 0x3180, "M S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"clearf", 0x05F0, 0x0A00, "f", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"cmp", 0x06C0, 0x0900, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpq", 0x02C0, 0x0D00, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"cmps", 0x08e0, 0x0300, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmps", 0x08e0, 0x0300, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"cmpu", 0x08c0, 0x0320, "z s,R" , 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpu", 0x08c0, 0x0320, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"di", 0x25F0, 0xDA0F, "", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"dip", DIP_OPCODE, DIP_Z_BITS, "ps", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_dip_prefix}, + + {"div", 0x0980, 0x0640, "m R,r", 0, SIZE_FIELD, 0, + cris_not_implemented_op}, + + {"dstep", 0x06f0, 0x0900, "r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"ei", 0x25B0, 0xDA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"fidxd", 0x0ab0, 0xf540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"fidxi", 0x0d30, 0xF2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagd", 0x1AB0, 0xE540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagi", 0x1D30, 0xE2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"halt", 0xF930, 0x06CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"jas", 0x09B0, 0x0640, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jas", 0x0DBF, 0x0240, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0B30, 0x04C0, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0F3F, 0x00C0, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jbrc", 0x69b0, 0x9640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA9b0, 0x5640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x29b0, 0xd640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB9b0, 0x4640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xBDBF, 0x4240, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x39b0, 0xc640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0xBB30, 0x44C0, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jsrc", 0xBF3F, 0x40C0, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jump", 0x09b0, 0xF640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", 0x09F0, 0x060F, "P", 0, SIZE_NONE, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_PC_INCR_OPCODE_V32, + (0xffff & ~JUMP_PC_INCR_OPCODE_V32), "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "s", 0, SIZE_FIX_32, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"lapc", 0x0970, 0x0680, "U,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapc", 0x0D7F, 0x0280, "dn,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapcq", 0x0970, 0x0680, "u,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"lsl", 0x04C0, 0x0B00, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lslq", 0x03c0, 0x0C20, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsr", 0x07C0, 0x0800, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsrq", 0x03e0, 0x0C00, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lz", 0x0730, 0x08C0, "r,R", 0, SIZE_NONE, + cris_ver_v3p, + cris_not_implemented_op}, + + {"mcp", 0x07f0, 0x0800, "P,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0640, 0x0980, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0630, 0x09c0, "r,P", 0, SIZE_NONE, 0, + cris_move_to_preg_op}, + + {"move", 0x0670, 0x0980, "P,r", 0, SIZE_NONE, 0, + cris_reg_mode_move_from_preg_op}, + + {"move", 0x0BC0, 0x0000, "m R,y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0BC0, 0x0000, "m D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", + MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS, + "s,P", 0, SIZE_SPEC_REG, 0, + cris_move_to_preg_op}, + + {"move", 0x0A30, 0x01c0, "S,P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"move", 0x0A70, 0x0180, "P,y", 0, SIZE_SPEC_REG, 0, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0A70, 0x0180, "P,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0B70, 0x0480, "r,T", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0F70, 0x0080, "T,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"movem", 0x0BF0, 0x0000, "R,y", 0, SIZE_FIX_32, 0, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BF0, 0x0000, "D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BB0, 0x0040, "s,R", 0, SIZE_FIX_32, 0, + cris_move_mem_to_reg_movem_op}, + + {"movem", 0x0BB0, 0x0040, "S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_mem_to_reg_movem_op}, + + {"moveq", 0x0240, 0x0D80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"movs", 0x0460, 0x0B80, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"movs", 0x0860, 0x0380, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movs", 0x0860, 0x0380, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0440, 0x0Ba0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"movu", 0x0840, 0x03a0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0840, 0x03a0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"mstep", 0x07f0, 0x0800, "r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_dstep_logshift_mstep_neg_not_op}, + + {"muls", 0x0d00, 0x02c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_muls_op}, + + {"mulu", 0x0900, 0x06c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_mulu_op}, + + {"neg", 0x0580, 0x0A40, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"nop", NOP_OPCODE, NOP_Z_BITS, "", 0, SIZE_NONE, + cris_ver_v0_10, + cris_btst_nop_op}, + + {"nop", NOP_OPCODE_V32, NOP_Z_BITS_V32, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_btst_nop_op}, + + {"not", 0x8770, 0x7880, "r", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"or", 0x0740, 0x0880, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0480, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"orq", 0x0340, 0x0C80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"pop", 0x0E6E, 0x0191, "!R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"pop", 0x0e3e, 0x01c1, "!P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"push", 0x0FEE, 0x0011, "BR", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"push", 0x0E7E, 0x0181, "BP", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"rbf", 0x3b30, 0xc0c0, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rbf", 0x3b30, 0xc0c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rfe", 0x2930, 0xD6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfg", 0x4930, 0xB6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfn", 0x5930, 0xA6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ret", 0xB67F, 0x4980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"ret", 0xB9F0, 0x460F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"retb", 0xe67f, 0x1980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"rete", 0xA9F0, 0x560F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"reti", 0xA67F, 0x5980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"retn", 0xC9F0, 0x360F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"sbfs", 0x3b70, 0xc080, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sbfs", 0x3b70, 0xc080, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sa", + 0x0530+CC_A*0x1000, + 0x0AC0+(0xf-CC_A)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"ssb", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_scc_op}, + + {"scc", + 0x0530+CC_CC*0x1000, + 0x0AC0+(0xf-CC_CC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"scs", + 0x0530+CC_CS*0x1000, + 0x0AC0+(0xf-CC_CS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"seq", + 0x0530+CC_EQ*0x1000, + 0x0AC0+(0xf-CC_EQ)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"setf", 0x05b0, 0x0A40, "f", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"sfe", 0x3930, 0xC6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + /* Need to have "swf" in front of "sext" so it is the one displayed in + disassembly. */ + {"swf", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v10, + cris_scc_op}, + + {"sext", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v0_3, + cris_scc_op}, + + {"sge", + 0x0530+CC_GE*0x1000, + 0x0AC0+(0xf-CC_GE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sgt", + 0x0530+CC_GT*0x1000, + 0x0AC0+(0xf-CC_GT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shi", + 0x0530+CC_HI*0x1000, + 0x0AC0+(0xf-CC_HI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shs", + 0x0530+CC_HS*0x1000, + 0x0AC0+(0xf-CC_HS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sle", + 0x0530+CC_LE*0x1000, + 0x0AC0+(0xf-CC_LE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slo", + 0x0530+CC_LO*0x1000, + 0x0AC0+(0xf-CC_LO)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sls", + 0x0530+CC_LS*0x1000, + 0x0AC0+(0xf-CC_LS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slt", + 0x0530+CC_LT*0x1000, + 0x0AC0+(0xf-CC_LT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"smi", + 0x0530+CC_MI*0x1000, + 0x0AC0+(0xf-CC_MI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sne", + 0x0530+CC_NE*0x1000, + 0x0AC0+(0xf-CC_NE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"spl", + 0x0530+CC_PL*0x1000, + 0x0AC0+(0xf-CC_PL)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sub", 0x0680, 0x0940, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0540, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subq", 0x0280, 0x0d40, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"subs", 0x04a0, 0x0b40, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"subs", 0x08a0, 0x0340, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0340, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0740, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subu", 0x0480, 0x0b60, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"subu", 0x0880, 0x0360, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0360, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0760, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"svc", + 0x0530+CC_VC*0x1000, + 0x0AC0+(0xf-CC_VC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"svs", + 0x0530+CC_VS*0x1000, + 0x0AC0+(0xf-CC_VS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + /* The insn "swapn" is the same as "not" and will be disassembled as + such, but the swap* family of mnmonics are generally v8-and-higher + only, so count it in. */ + {"swapn", 0x8770, 0x7880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapw", 0x4770, 0xb880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnw", 0xc770, 0x3880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapb", 0x2770, 0xd880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnb", 0xA770, 0x5880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwb", 0x6770, 0x9880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwb", 0xE770, 0x1880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapr", 0x1770, 0xe880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnr", 0x9770, 0x6880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwr", 0x5770, 0xa880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwr", 0xd770, 0x2880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapbr", 0x3770, 0xc880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnbr", 0xb770, 0x4880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwbr", 0x7770, 0x8880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwbr", 0xf770, 0x0880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"test", 0x0640, 0x0980, "m D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_test_op}, + + {"test", 0x0b80, 0xf040, "m y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_clear_test_op}, + + {"test", 0x0b80, 0xf040, "m S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"xor", 0x07B0, 0x0840, "r,R", 0, SIZE_NONE, 0, + cris_xor_op}, + + {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op} +}; + +/* Condition-names, indexed by the CC_* numbers as found in cris.h. */ +const char * const +cris_cc_strings[] = +{ + "hs", + "lo", + "ne", + "eq", + "vc", + "vs", + "pl", + "mi", + "ls", + "hi", + "ge", + "lt", + "gt", + "le", + "a", + /* This is a placeholder. In v0, this would be "ext". In v32, this + is "sb". See cris_conds15. */ + "wf" +}; + +/* Different names and semantics for condition 1111 (0xf). */ +const struct cris_cond15 cris_cond15s[] = +{ + /* FIXME: In what version did condition "ext" disappear? */ + {"ext", cris_ver_v0_3}, + {"wf", cris_ver_v10}, + {"sb", cris_ver_v32p}, + {NULL, 0} +}; + + +/* + * Local variables: + * eval: (c-set-style "gnu") + * indent-tabs-mode: t + * End: + */ + + +/* No instruction will be disassembled longer than this. In theory, and + in silicon, address prefixes can be cascaded. In practice, cascading + is not used by GCC, and not supported by the assembler. */ +#ifndef MAX_BYTES_PER_CRIS_INSN +#define MAX_BYTES_PER_CRIS_INSN 8 +#endif + +/* Whether or not to decode prefixes, folding it into the following + instruction. FIXME: Make this optional later. */ +#ifndef PARSE_PREFIX +#define PARSE_PREFIX 1 +#endif + +/* Sometimes we prefix all registers with this character. */ +#define REGISTER_PREFIX_CHAR '$' + +/* Whether or not to trace the following sequence: + sub* X,r%d + bound* Y,r%d + adds.w [pc+r%d.w],pc + + This is the assembly form of a switch-statement in C. + The "sub is optional. If there is none, then X will be zero. + X is the value of the first case, + Y is the number of cases (including default). + + This results in case offsets printed on the form: + case N: -> case_address + where N is an estimation on the corresponding 'case' operand in C, + and case_address is where execution of that case continues after the + sequence presented above. + + The old style of output was to print the offsets as instructions, + which made it hard to follow "case"-constructs in the disassembly, + and caused a lot of annoying warnings about undefined instructions. + + FIXME: Make this optional later. */ +#ifndef TRACE_CASE +#define TRACE_CASE (disdata->trace_case) +#endif + +enum cris_disass_family + { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 }; + +/* Stored in the disasm_info->private_data member. */ +struct cris_disasm_data +{ + /* Whether to print something less confusing if we find something + matching a switch-construct. */ + bfd_boolean trace_case; + + /* Whether this code is flagged as crisv32. FIXME: Should be an enum + that includes "compatible". */ + enum cris_disass_family distype; +}; + +/* Value of first element in switch. */ +static long case_offset = 0; + +/* How many more case-offsets to print. */ +static long case_offset_counter = 0; + +/* Number of case offsets. */ +static long no_of_case_offsets = 0; + +/* Candidate for next case_offset. */ +static long last_immediate = 0; + +static int cris_constraint + (const char *, unsigned, unsigned, struct cris_disasm_data *); + +/* Parse disassembler options and store state in info. FIXME: For the + time being, we abuse static variables. */ + +static bfd_boolean +cris_parse_disassembler_options (disassemble_info *info, + enum cris_disass_family distype) +{ + struct cris_disasm_data *disdata; + + info->private_data = calloc (1, sizeof (struct cris_disasm_data)); + disdata = (struct cris_disasm_data *) info->private_data; + if (disdata == NULL) + return false; + + /* Default true. */ + disdata->trace_case + = (info->disassembler_options == NULL + || (strcmp (info->disassembler_options, "nocase") != 0)); + + disdata->distype = distype; + return true; +} + +static const struct cris_spec_reg * +spec_reg_info (unsigned int sreg, enum cris_disass_family distype) +{ + int i; + + for (i = 0; cris_spec_regs[i].name != NULL; i++) + { + if (cris_spec_regs[i].number == sreg) + { + if (distype == cris_dis_v32) + switch (cris_spec_regs[i].applicable_version) + { + case cris_ver_warning: + case cris_ver_version_all: + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + /* No ambiguous sizes or register names with CRISv32. */ + if (cris_spec_regs[i].warning == NULL) + return &cris_spec_regs[i]; + default: + ; + } + else if (cris_spec_regs[i].applicable_version != cris_ver_v32p) + return &cris_spec_regs[i]; + } + } + + return NULL; +} + +/* Return the number of bits in the argument. */ + +static int +number_of_bits (unsigned int val) +{ + int bits; + + for (bits = 0; val != 0; val &= val - 1) + bits++; + + return bits; +} + +/* Get an entry in the opcode-table. */ + +static const struct cris_opcode * +get_opcode_entry (unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + /* For non-prefixed insns, we keep a table of pointers, indexed by the + insn code. Each entry is initialized when found to be NULL. */ + static const struct cris_opcode **opc_table = NULL; + + const struct cris_opcode *max_matchedp = NULL; + const struct cris_opcode **prefix_opc_table = NULL; + + /* We hold a table for each prefix that need to be handled differently. */ + static const struct cris_opcode **dip_prefixes = NULL; + static const struct cris_opcode **bdapq_m1_prefixes = NULL; + static const struct cris_opcode **bdapq_m2_prefixes = NULL; + static const struct cris_opcode **bdapq_m4_prefixes = NULL; + static const struct cris_opcode **rest_prefixes = NULL; + + /* Allocate and clear the opcode-table. */ + if (opc_table == NULL) + { + opc_table = qemu_malloc (65536 * sizeof (opc_table[0])); + + memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *)); + + dip_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0])); + + bdapq_m1_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0])); + + bdapq_m2_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0])); + + bdapq_m4_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0])); + + rest_prefixes + = qemu_malloc (65536 * sizeof (const struct cris_opcode **)); + + memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0])); + } + + /* Get the right table if this is a prefix. + This code is connected to cris_constraints in that it knows what + prefixes play a role in recognition of patterns; the necessary + state is reflected by which table is used. If constraints + involving match or non-match of prefix insns are changed, then this + probably needs changing too. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + const struct cris_opcode *popcodep + = (opc_table[prefix_insn] != NULL + ? opc_table[prefix_insn] + : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata)); + + if (popcodep == NULL) + return NULL; + + if (popcodep->match == BDAP_QUICK_OPCODE) + { + /* Since some offsets are recognized with "push" macros, we + have to have different tables for them. */ + int offset = (prefix_insn & 255); + + if (offset > 127) + offset -= 256; + + switch (offset) + { + case -4: + prefix_opc_table = bdapq_m4_prefixes; + break; + + case -2: + prefix_opc_table = bdapq_m2_prefixes; + break; + + case -1: + prefix_opc_table = bdapq_m1_prefixes; + break; + + default: + prefix_opc_table = rest_prefixes; + break; + } + } + else if (popcodep->match == DIP_OPCODE) + /* We don't allow postincrement when the prefix is DIP, so use a + different table for DIP. */ + prefix_opc_table = dip_prefixes; + else + prefix_opc_table = rest_prefixes; + } + + if (prefix_insn != NO_CRIS_PREFIX + && prefix_opc_table[insn] != NULL) + max_matchedp = prefix_opc_table[insn]; + else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) + max_matchedp = opc_table[insn]; + else + { + const struct cris_opcode *opcodep; + int max_level_of_match = -1; + + for (opcodep = cris_opcodes; + opcodep->name != NULL; + opcodep++) + { + int level_of_match; + + if (disdata->distype == cris_dis_v32) + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + break; + + case cris_ver_v0_3: + case cris_ver_v0_10: + case cris_ver_v3_10: + case cris_ver_sim_v0_10: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_warning: + continue; + + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + break; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + else + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + case cris_ver_v0_3: + case cris_ver_v3p: + case cris_ver_v0_10: + case cris_ver_v8p: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_sim_v0_10: + case cris_ver_v10p: + case cris_ver_warning: + break; + + case cris_ver_v32p: + continue; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + + /* We give a double lead for bits matching the template in + cris_opcodes. Not even, because then "move p8,r10" would + be given 2 bits lead over "clear.d r10". When there's a + tie, the first entry in the table wins. This is + deliberate, to avoid a more complicated recognition + formula. */ + if ((opcodep->match & insn) == opcodep->match + && (opcodep->lose & insn) == 0 + && ((level_of_match + = cris_constraint (opcodep->args, + insn, + prefix_insn, + disdata)) + >= 0) + && ((level_of_match + += 2 * number_of_bits (opcodep->match + | opcodep->lose)) + > max_level_of_match)) + { + max_matchedp = opcodep; + max_level_of_match = level_of_match; + + /* If there was a full match, never mind looking + further. */ + if (level_of_match >= 2 * 16) + break; + } + } + /* Fill in the new entry. + + If there are changes to the opcode-table involving prefixes, and + disassembly then does not work correctly, try removing the + else-clause below that fills in the prefix-table. If that + helps, you need to change the prefix_opc_table setting above, or + something related. */ + if (prefix_insn == NO_CRIS_PREFIX) + opc_table[insn] = max_matchedp; + else + prefix_opc_table[insn] = max_matchedp; + } + + return max_matchedp; +} + +/* Return -1 if the constraints of a bitwise-matched instruction say + that there is no match. Otherwise return a nonnegative number + indicating the confidence in the match (higher is better). */ + +static int +cris_constraint (const char *cs, + unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + int retval = 0; + int tmp; + int prefix_ok = 0; + const char *s; + + for (s = cs; *s; s++) + switch (*s) + { + case '!': + /* Do not recognize "pop" if there's a prefix and then only for + v0..v10. */ + if (prefix_insn != NO_CRIS_PREFIX + || disdata->distype != cris_dis_v0_v10) + return -1; + break; + + case 'U': + /* Not recognized at disassembly. */ + return -1; + + case 'M': + /* Size modifier for "clear", i.e. special register 0, 4 or 8. + Check that it is one of them. Only special register 12 could + be mismatched, but checking for matches is more logical than + checking for mismatches when there are only a few cases. */ + tmp = ((insn >> 12) & 0xf); + if (tmp != 0 && tmp != 4 && tmp != 8) + return -1; + break; + + case 'm': + if ((insn & 0x30) == 0x30) + return -1; + break; + + case 'S': + /* A prefix operand without side-effect. */ + if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) + { + prefix_ok = 1; + break; + } + else + return -1; + + case 's': + case 'y': + case 'Y': + /* If this is a prefixed insn with postincrement (side-effect), + the prefix must not be DIP. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + if (insn & 0x400) + { + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == DIP_OPCODE) + return -1; + } + + prefix_ok = 1; + } + break; + + case 'B': + /* If we don't fall through, then the prefix is ok. */ + prefix_ok = 1; + + /* A "push" prefix. Check for valid "push" size. + In case of special register, it may be != 4. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + /* Match the prefix insn to BDAPQ. */ + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == BDAP_QUICK_OPCODE) + { + int pushsize = (prefix_insn & 255); + + if (pushsize > 127) + pushsize -= 256; + + if (s[1] == 'P') + { + unsigned int spec_reg = (insn >> 12) & 15; + const struct cris_spec_reg *sregp + = spec_reg_info (spec_reg, disdata->distype); + + /* For a special-register, the "prefix size" must + match the size of the register. */ + if (sregp && sregp->reg_size == (unsigned int) -pushsize) + break; + } + else if (s[1] == 'R') + { + if ((insn & 0x30) == 0x20 && pushsize == -4) + break; + } + /* FIXME: Should abort here; next constraint letter + *must* be 'P' or 'R'. */ + } + } + return -1; + + case 'D': + retval = (((insn >> 12) & 15) == (insn & 15)); + if (!retval) + return -1; + else + retval += 4; + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* Since we match four bits, we will give a value of 4-1 = 3 + in a match. If there is a corresponding exact match of a + special register in another pattern, it will get a value of + 4, which will be higher. This should be correct in that an + exact pattern would match better than a general pattern. + + Note that there is a reason for not returning zero; the + pattern for "clear" is partly matched in the bit-pattern + (the two lower bits must be zero), while the bit-pattern + for a move from a special register is matched in the + register constraint. */ + + if (sregp != NULL) + { + retval += 3; + break; + } + else + return -1; + } + } + + if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) + return -1; + + return retval; +} + +/* Format number as hex with a leading "0x" into outbuffer. */ + +static char * +format_hex (unsigned long number, + char *outbuffer, + struct cris_disasm_data *disdata) +{ + /* Truncate negative numbers on >32-bit hosts. */ + number &= 0xffffffff; + + sprintf (outbuffer, "0x%lx", number); + + /* Save this value for the "case" support. */ + if (TRACE_CASE) + last_immediate = number; + + return outbuffer + strlen (outbuffer); +} + +/* Format number as decimal into outbuffer. Parameter signedp says + whether the number should be formatted as signed (!= 0) or + unsigned (== 0). */ + +static char * +format_dec (long number, char *outbuffer, int signedp) +{ + last_immediate = number; + sprintf (outbuffer, signedp ? "%ld" : "%lu", number); + + return outbuffer + strlen (outbuffer); +} + +/* Format the name of the general register regno into outbuffer. */ + +static char * +format_reg (struct cris_disasm_data *disdata, + int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + switch (regno) + { + case 15: + /* For v32, there is no context in which we output PC. */ + if (disdata->distype == cris_dis_v32) + strcpy (outbuffer, "acr"); + else + strcpy (outbuffer, "pc"); + break; + + case 14: + strcpy (outbuffer, "sp"); + break; + + default: + sprintf (outbuffer, "r%d", regno); + break; + } + + return outbuffer_start + strlen (outbuffer_start); +} + +/* Format the name of a support register into outbuffer. */ + +static char * +format_sup_reg (unsigned int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + int i; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + for (i = 0; cris_support_regs[i].name != NULL; i++) + if (cris_support_regs[i].number == regno) + { + sprintf (outbuffer, "%s", cris_support_regs[i].name); + return outbuffer_start + strlen (outbuffer_start); + } + + /* There's supposed to be register names covering all numbers, though + some may be generic names. */ + sprintf (outbuffer, "format_sup_reg-BUG"); + return outbuffer_start + strlen (outbuffer_start); +} + +/* Return the length of an instruction. */ + +static unsigned +bytes_to_skip (unsigned int insn, + const struct cris_opcode *matchedp, + enum cris_disass_family distype, + const struct cris_opcode *prefix_matchedp) +{ + /* Each insn is a word plus "immediate" operands. */ + unsigned to_skip = 2; + const char *template = matchedp->args; + const char *s; + + for (s = template; *s; s++) + if ((*s == 's' || *s == 'N' || *s == 'Y') + && (insn & 0x400) && (insn & 15) == 15 + && prefix_matchedp == NULL) + { + /* Immediate via [pc+], so we have to check the size of the + operand. */ + int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); + + if (matchedp->imm_oprnd_size == SIZE_FIX_32) + to_skip += 4; + else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + return 2; + + /* PC is incremented by two, not one, for a byte. Except on + CRISv32, where constants are always DWORD-size for + special registers. */ + to_skip += + distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; + } + else + to_skip += (mode_size + 1) & ~1; + } + else if (*s == 'n') + to_skip += 4; + else if (*s == 'b') + to_skip += 2; + + return to_skip; +} + +/* Print condition code flags. */ + +static char * +print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp) +{ + /* Use the v8 (Etrax 100) flag definitions for disassembly. + The differences with v0 (Etrax 1..4) vs. Svinto are: + v0 'd' <=> v8 'm' + v0 'e' <=> v8 'b'. + FIXME: Emit v0..v3 flag names somehow. */ + static const char v8_fnames[] = "cvznxibm"; + static const char v32_fnames[] = "cvznxiup"; + const char *fnames + = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames; + + unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); + int i; + + for (i = 0; i < 8; i++) + if (flagbits & (1 << i)) + *cp++ = fnames[i]; + + return cp; +} + +/* Print out an insn with its operands, and update the info->insn_type + fields. The prefix_opcodep and the rest hold a prefix insn that is + supposed to be output as an address mode. */ + +static void +print_with_operands (const struct cris_opcode *opcodep, + unsigned int insn, + unsigned char *buffer, + bfd_vma addr, + disassemble_info *info, + /* If a prefix insn was before this insn (and is supposed + to be output as an address), here is a description of + it. */ + const struct cris_opcode *prefix_opcodep, + unsigned int prefix_insn, + unsigned char *prefix_buffer, + bfd_boolean with_reg_prefix) +{ + /* Get a buffer of somewhat reasonable size where we store + intermediate parts of the insn. */ + char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; + char *tp = temp; + static const char mode_char[] = "bwd?"; + const char *s; + const char *cs; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* Print out the name first thing we do. */ + (*info->fprintf_func) (info->stream, "%s", opcodep->name); + + cs = opcodep->args; + s = cs; + + /* Ignore any prefix indicator. */ + if (*s == 'p') + s++; + + if (*s == 'm' || *s == 'M' || *s == 'z') + { + *tp++ = '.'; + + /* Get the size-letter. */ + *tp++ = *s == 'M' + ? (insn & 0x8000 ? 'd' + : insn & 0x4000 ? 'w' : 'b') + : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; + + /* Ignore the size and the space character that follows. */ + s += 2; + } + + /* Add a space if this isn't a long-branch, because for those will add + the condition part of the name later. */ + if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) + *tp++ = ' '; + + /* Fill in the insn-type if deducible from the name (and there's no + better way). */ + if (opcodep->name[0] == 'j') + { + if (CONST_STRNEQ (opcodep->name, "jsr")) + /* It's "jsr" or "jsrc". */ + info->insn_type = dis_jsr; + else + /* Any other jump-type insn is considered a branch. */ + info->insn_type = dis_branch; + } + + /* We might know some more fields right now. */ + info->branch_delay_insns = opcodep->delayed; + + /* Handle operands. */ + for (; *s; s++) + { + switch (*s) + { + case 'T': + tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'A': + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + *tp++ = 'a'; + *tp++ = 'c'; + *tp++ = 'r'; + break; + + case '[': + case ']': + case ',': + *tp++ = *s; + break; + + case '!': + /* Ignore at this point; used at earlier stages to avoid + recognition if there's a prefix at something that in other + ways looks like a "pop". */ + break; + + case 'd': + /* Ignore. This is an optional ".d " on the large one of + relaxable insns. */ + break; + + case 'B': + /* This was the prefix that made this a "push". We've already + handled it by recognizing it, so signal that the prefix is + handled by setting it to NULL. */ + prefix_opcodep = NULL; + break; + + case 'D': + case 'r': + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + break; + + case 'R': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'n': + { + /* Like N but pc-relative to the start of the insn. */ + unsigned long number + = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000 + addr); + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'u': + { + /* Like n but the offset is bits <3:0> in the instruction. */ + unsigned long number = (buffer[0] & 0xf) * 2 + addr; + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'N': + case 'y': + case 'Y': + case 'S': + case 's': + /* Any "normal" memory operand. */ + if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL) + { + /* We're looking at [pc+], i.e. we need to output an immediate + number, where the size can depend on different things. */ + long number; + int signedp + = ((*cs == 'z' && (insn & 0x20)) + || opcodep->match == BDAP_QUICK_OPCODE); + int nbytes; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + nbytes = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* A NULL return should have been as a non-match earlier, + so catch it as an internal error in the error-case + below. */ + if (sregp == NULL) + /* Whatever non-valid size. */ + nbytes = 42; + else + /* PC is always incremented by a multiple of two. + For CRISv32, immediates are always 4 bytes for + special registers. */ + nbytes = disdata->distype == cris_dis_v32 + ? 4 : (sregp->reg_size + 1) & ~1; + } + else + { + int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + } + + switch (nbytes) + { + case 1: + number = buffer[2]; + if (signedp && number > 127) + number -= 256; + break; + + case 2: + number = buffer[2] + buffer[3] * 256; + if (signedp && number > 32767) + number -= 65536; + break; + + case 4: + number + = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + if ((*cs == 'z' && (insn & 0x20)) + || (opcodep->match == BDAP_QUICK_OPCODE + && (nbytes <= 2 || buffer[1 + nbytes] == 0))) + tp = format_dec (number, tp, signedp); + else + { + unsigned int highbyte = (number >> 24) & 0xff; + + /* Either output this as an address or as a number. If it's + a dword with the same high-byte as the address of the + insn, assume it's an address, and also if it's a non-zero + non-0xff high-byte. If this is a jsr or a jump, then + it's definitely an address. */ + if (nbytes == 4 + && (highbyte == ((addr >> 24) & 0xff) + || (highbyte != 0 && highbyte != 0xff) + || info->insn_type == dis_branch + || info->insn_type == dis_jsr)) + { + /* Finish off and output previous formatted bytes. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + + info->target = number; + } + else + tp = format_hex (number, tp, disdata); + } + } + else + { + /* Not an immediate number. Then this is a (possibly + prefixed) memory operand. */ + if (info->insn_type != dis_nonbranch) + { + int mode_size + = 1 << ((insn >> 4) + & (opcodep->args[0] == 'z' ? 1 : 3)); + int size; + info->insn_type = dis_dref; + info->flags |= CRIS_DIS_FLAG_MEMREF; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + size = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + size = 4; + else + size = sregp->reg_size; + } + else + size = mode_size; + + info->data_size = size; + } + + *tp++ = '['; + + if (prefix_opcodep + /* We don't match dip with a postincremented field + as a side-effect address mode. */ + && ((insn & 0x400) == 0 + || prefix_opcodep->match != DIP_OPCODE)) + { + if (insn & 0x400) + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + *tp++ = '='; + } + + + /* We mainly ignore the prefix format string when the + address-mode syntax is output. */ + switch (prefix_opcodep->match) + { + case DIP_OPCODE: + /* It's [r], [r+] or [pc+]. */ + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + /* It's [pc+]. This cannot possibly be anything + but an address. */ + unsigned long number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + + info->target = (bfd_vma) number; + + /* Finish off and output previous formatted + data. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + /* For a memref in an address, we use target2. + In this case, target is zero. */ + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM); + + info->target2 = prefix_insn & 15; + + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + } + break; + + case BDAP_QUICK_OPCODE: + { + int number; + + number = prefix_buffer[0]; + if (number > 127) + number -= 256; + + /* Output "reg+num" or, if num < 0, "reg-num". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = (prefix_insn >> 12) & 15; + info->target2 = (bfd_vma) number; + break; + } + + case BIAP_OPCODE: + /* Output "r+R.m". */ + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + *tp++ = '+'; + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4 + : ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0))); + + /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */ + if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f) + /* Then start interpreting data as offsets. */ + case_offset_counter = no_of_case_offsets; + break; + + case BDAP_INDIR_OPCODE: + /* Output "r+s.m", or, if "s" is [pc+], "r+s" or + "r-s". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + long number; + unsigned int nbytes; + + /* It's a value. Get its size. */ + int mode_size = 1 << ((prefix_insn >> 4) & 3); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + + switch (nbytes) + { + case 1: + number = prefix_buffer[2]; + if (number > 127) + number -= 256; + break; + + case 2: + number = prefix_buffer[2] + prefix_buffer[3] * 256; + if (number > 32767) + number -= 65536; + break; + + case 4: + number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target2 = (bfd_vma) number; + + /* If the size is dword, then assume it's an + address. */ + if (nbytes == 4) + { + /* Finish off and output previous formatted + bytes. */ + *tp++ = '+'; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + } + } + else + { + /* Output "r+[R].m" or "r+[R+].m". */ + *tp++ = '+'; + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | (((prefix_insn >> 4) == 2) + ? 0 + : (((prefix_insn >> 4) & 3) == 1 + ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD + : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE))); + } + break; + + default: + (*info->fprintf_func) (info->stream, "?prefix-bug"); + } + + /* To mark that the prefix is used, reset it. */ + prefix_opcodep = NULL; + } + else + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = insn & 15; + + if (insn & 0x400) + *tp++ = '+'; + } + *tp++ = ']'; + } + break; + + case 'x': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(insn >> 4) & 3]; + break; + + case 'I': + tp = format_dec (insn & 63, tp, 0); + break; + + case 'b': + { + int where = buffer[2] + buffer[3] * 256; + + if (where > 32767) + where -= 65536; + + where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4); + + if (insn == BA_PC_INCR_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + info->target = (bfd_vma) where; + + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s%s ", + temp, cris_cc_strings[insn >> 12]); + + (*info->print_address_func) ((bfd_vma) where, info); + } + break; + + case 'c': + tp = format_dec (insn & 31, tp, 0); + break; + + case 'C': + tp = format_dec (insn & 15, tp, 0); + break; + + case 'o': + { + long offset = insn & 0xfe; + bfd_vma target; + + if (insn & 1) + offset |= ~0xff; + + if (opcodep->match == BA_QUICK_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset; + info->target = target; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + (*info->print_address_func) (target, info); + } + break; + + case 'Q': + case 'O': + { + long number = buffer[0]; + + if (number > 127) + number = number - 256; + + tp = format_dec (number, tp, 1); + *tp++ = ','; + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + } + break; + + case 'f': + tp = print_flags (disdata, insn, tp); + break; + + case 'i': + tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1); + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + if (sregp->name == NULL) + /* Should have been caught as a non-match eariler. */ + *tp++ = '?'; + else + { + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + strcpy (tp, sregp->name); + tp += strlen (tp); + } + } + break; + + default: + strcpy (tp, "???"); + tp += 3; + } + } + + *tp = 0; + + if (prefix_opcodep) + (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")", + prefix_opcodep->name, prefix_opcodep->args); + + (*info->fprintf_func) (info->stream, "%s", temp); + + /* Get info for matching case-tables, if we don't have any active. + We assume that the last constant seen is used; either in the insn + itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */ + if (TRACE_CASE && case_offset_counter == 0) + { + if (CONST_STRNEQ (opcodep->name, "sub")) + case_offset = last_immediate; + + /* It could also be an "add", if there are negative case-values. */ + else if (CONST_STRNEQ (opcodep->name, "add")) + /* The first case is the negated operand to the add. */ + case_offset = -last_immediate; + + /* A bound insn will tell us the number of cases. */ + else if (CONST_STRNEQ (opcodep->name, "bound")) + no_of_case_offsets = last_immediate + 1; + + /* A jump or jsr or branch breaks the chain of insns for a + case-table, so assume default first-case again. */ + else if (info->insn_type == dis_jsr + || info->insn_type == dis_branch + || info->insn_type == dis_condbranch) + case_offset = 0; + } +} + + +/* Print the CRIS instruction at address memaddr on stream. Returns + length of the instruction, in bytes. Prefix register names with `$' if + WITH_REG_PREFIX. */ + +static int +print_insn_cris_generic (bfd_vma memaddr, + disassemble_info *info, + bfd_boolean with_reg_prefix) +{ + int nbytes; + unsigned int insn; + const struct cris_opcode *matchedp; + int advance = 0; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* No instruction will be disassembled as longer than this number of + bytes; stacked prefixes will not be expanded. */ + unsigned char buffer[MAX_BYTES_PER_CRIS_INSN]; + unsigned char *bufp; + int status = 0; + bfd_vma addr; + + /* There will be an "out of range" error after the last instruction. + Reading pairs of bytes in decreasing number, we hope that we will get + at least the amount that we will consume. + + If we can't get any data, or we do not get enough data, we print + the error message. */ + + nbytes = info->buffer_length; + if (nbytes > MAX_BYTES_PER_CRIS_INSN) + nbytes = MAX_BYTES_PER_CRIS_INSN; + status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); + + /* If we did not get all we asked for, then clear the rest. + Hopefully this makes a reproducible result in case of errors. */ + if (nbytes != MAX_BYTES_PER_CRIS_INSN) + memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes); + + addr = memaddr; + bufp = buffer; + + /* Set some defaults for the insn info. */ + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->flags = 0; + info->target = 0; + info->target2 = 0; + + /* If we got any data, disassemble it. */ + if (nbytes != 0) + { + matchedp = NULL; + + insn = bufp[0] + bufp[1] * 256; + + /* If we're in a case-table, don't disassemble the offsets. */ + if (TRACE_CASE && case_offset_counter != 0) + { + info->insn_type = dis_noninsn; + advance += 2; + + /* If to print data as offsets, then shortcut here. */ + (*info->fprintf_func) (info->stream, "case %ld%s: -> ", + case_offset + no_of_case_offsets + - case_offset_counter, + case_offset_counter == 1 ? "/default" : + ""); + + (*info->print_address_func) ((bfd_vma) + ((short) (insn) + + (long) (addr + - (no_of_case_offsets + - case_offset_counter) + * 2)), info); + case_offset_counter--; + + /* The default case start (without a "sub" or "add") must be + zero. */ + if (case_offset_counter == 0) + case_offset = 0; + } + else if (insn == 0) + { + /* We're often called to disassemble zeroes. While this is a + valid "bcc .+2" insn, it is also useless enough and enough + of a nuiscance that we will just output "bcc .+2" for it + and signal it as a noninsn. */ + (*info->fprintf_func) (info->stream, + disdata->distype == cris_dis_v32 + ? "bcc ." : "bcc .+2"); + info->insn_type = dis_noninsn; + advance += 2; + } + else + { + const struct cris_opcode *prefix_opcodep = NULL; + unsigned char *prefix_buffer = bufp; + unsigned int prefix_insn = insn; + int prefix_size = 0; + + matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata); + + /* Check if we're supposed to write out prefixes as address + modes and if this was a prefix. */ + if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p') + { + /* If it's a prefix, put it into the prefix vars and get the + main insn. */ + prefix_size = bytes_to_skip (prefix_insn, matchedp, + disdata->distype, NULL); + prefix_opcodep = matchedp; + + insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256; + matchedp = get_opcode_entry (insn, prefix_insn, disdata); + + if (matchedp != NULL) + { + addr += prefix_size; + bufp += prefix_size; + advance += prefix_size; + } + else + { + /* The "main" insn wasn't valid, at least not when + prefixed. Put back things enough to output the + prefix insn only, as a normal insn. */ + matchedp = prefix_opcodep; + insn = prefix_insn; + prefix_opcodep = NULL; + } + } + + if (matchedp == NULL) + { + (*info->fprintf_func) (info->stream, "??0x%x", insn); + advance += 2; + + info->insn_type = dis_noninsn; + } + else + { + advance + += bytes_to_skip (insn, matchedp, disdata->distype, + prefix_opcodep); + + /* The info_type and assorted fields will be set according + to the operands. */ + print_with_operands (matchedp, insn, bufp, addr, info, + prefix_opcodep, prefix_insn, + prefix_buffer, with_reg_prefix); + } + } + } + else + info->insn_type = dis_noninsn; + + /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error + status when reading that much, and the insn decoding indicated a + length exceeding what we read, there is an error. */ + if (status != 0 && (nbytes == 0 || advance > nbytes)) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + /* Max supported insn size with one folded prefix insn. */ + info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN; + + /* I would like to set this to a fixed value larger than the actual + number of bytes to print in order to avoid spaces between bytes, + but objdump.c (2.9.1) does not like that, so we print 16-bit + chunks, which is the next choice. */ + info->bytes_per_chunk = 2; + + /* Printing bytes in order of increasing addresses makes sense, + especially on a little-endian target. + This is completely the opposite of what you think; setting this to + BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N + we want. */ + info->display_endian = BFD_ENDIAN_BIG; + + return advance; +} + +/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */ +#if 0 +static int +print_insn_cris_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, true); +} +#endif +/* Disassemble, prefixing register names with `$'. CRIS v32. */ + +static int +print_insn_crisv32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, true); +} + +#if 0 +/* Disassemble, prefixing register names with `$'. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, true); +} + +/* Disassemble, no prefixes on register names. CRIS v0..v10. */ + +static int +print_insn_cris_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, false); +} + +/* Disassemble, no prefixes on register names. CRIS v32. */ + +static int +print_insn_crisv32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, false); +} + +/* Disassemble, no prefixes on register names. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, false); +} +#endif + +int +print_insn_crisv32 (bfd_vma vma, + disassemble_info *info) +{ + return print_insn_crisv32_with_register_prefix(vma, info); +} + +/* Return a disassembler-function that prints registers with a `$' prefix, + or one that prints registers without a prefix. + FIXME: We should improve the solution to avoid the multitude of + functions seen above. */ +#if 0 +disassembler_ftype +cris_get_disassembler (bfd *abfd) +{ + /* If there's no bfd in sight, we return what is valid as input in all + contexts if fed back to the assembler: disassembly *with* register + prefix. Unfortunately this will be totally wrong for v32. */ + if (abfd == NULL) + return print_insn_cris_with_register_prefix; + + if (bfd_get_symbol_leading_char (abfd) == 0) + { + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_with_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_with_register_prefix; + + /* We default to v10. This may be specifically specified in the + bfd mach, but is also the default setting. */ + return print_insn_cris_with_register_prefix; + } + + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_without_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_without_register_prefix; + return print_insn_cris_without_register_prefix; +} +#endif +/* Local variables: + eval: (c-set-style "gnu") + indent-tabs-mode: t + End: */ diff --git a/qemu/qemu-git/cutils.c b/qemu/qemu-git/cutils.c new file mode 100644 index 0000000..5b2561c --- /dev/null +++ b/qemu/qemu-git/cutils.c @@ -0,0 +1,237 @@ +/* + * Simple C functions to supplement the C library + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "host-utils.h" + +void pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for(;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +/* strcat and truncate. */ +char *pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +int strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +int stristart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (qemu_toupper(*p) != qemu_toupper(*q)) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +/* XXX: use host strnlen if available ? */ +int qemu_strnlen(const char *s, int max_len) +{ + int i; + + for(i = 0; i < max_len; i++) { + if (s[i] == '\0') { + break; + } + } + return i; +} + +time_t mktimegm(struct tm *tm) +{ + time_t t; + int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; + if (m < 3) { + m += 12; + y--; + } + t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + + y / 400 - 719469); + t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; + return t; +} + +int qemu_fls(int i) +{ + return 32 - clz32(i); +} + +/* + * Make sure data goes on disk, but if possible do not bother to + * write out the inode just for timestamp updates. + * + * Unfortunately even in 2009 many operating systems do not support + * fdatasync and have to fall back to fsync. + */ +int qemu_fdatasync(int fd) +{ +#ifdef CONFIG_FDATASYNC + return fdatasync(fd); +#else + return fsync(fd); +#endif +} + +#ifndef X49GP +/* io vectors */ + +void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint) +{ + qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec)); + qiov->niov = 0; + qiov->nalloc = alloc_hint; + qiov->size = 0; +} + +void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov) +{ + int i; + + qiov->iov = iov; + qiov->niov = niov; + qiov->nalloc = -1; + qiov->size = 0; + for (i = 0; i < niov; i++) + qiov->size += iov[i].iov_len; +} + +void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) +{ + assert(qiov->nalloc != -1); + + if (qiov->niov == qiov->nalloc) { + qiov->nalloc = 2 * qiov->nalloc + 1; + qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec)); + } + qiov->iov[qiov->niov].iov_base = base; + qiov->iov[qiov->niov].iov_len = len; + qiov->size += len; + ++qiov->niov; +} + +/* + * Copies iovecs from src to the end dst until src is completely copied or the + * total size of the copied iovec reaches size. The size of the last copied + * iovec is changed in order to fit the specified total size if it isn't a + * perfect fit already. + */ +void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size) +{ + int i; + size_t done; + + assert(dst->nalloc != -1); + + done = 0; + for (i = 0; (i < src->niov) && (done != size); i++) { + if (done + src->iov[i].iov_len > size) { + qemu_iovec_add(dst, src->iov[i].iov_base, size - done); + break; + } else { + qemu_iovec_add(dst, src->iov[i].iov_base, src->iov[i].iov_len); + } + done += src->iov[i].iov_len; + } +} + +void qemu_iovec_destroy(QEMUIOVector *qiov) +{ + assert(qiov->nalloc != -1); + + qemu_free(qiov->iov); +} + +void qemu_iovec_reset(QEMUIOVector *qiov) +{ + assert(qiov->nalloc != -1); + + qiov->niov = 0; + qiov->size = 0; +} + +void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf) +{ + uint8_t *p = (uint8_t *)buf; + int i; + + for (i = 0; i < qiov->niov; ++i) { + memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); + p += qiov->iov[i].iov_len; + } +} + +void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) +{ + const uint8_t *p = (const uint8_t *)buf; + size_t copy; + int i; + + for (i = 0; i < qiov->niov && count; ++i) { + copy = count; + if (copy > qiov->iov[i].iov_len) + copy = qiov->iov[i].iov_len; + memcpy(qiov->iov[i].iov_base, p, copy); + p += copy; + count -= copy; + } +} +#endif diff --git a/qemu/qemu-git/def-helper.h b/qemu/qemu-git/def-helper.h new file mode 100644 index 0000000..8a88c5b --- /dev/null +++ b/qemu/qemu-git/def-helper.h @@ -0,0 +1,220 @@ +/* Helper file for declaring TCG helper functions. + Should be included at the start and end of target-foo/helper.h. + + Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper + functions. Names should be specified without the helper_ prefix, and + the return and argument types specified. 3 basic types are understood + (i32, i64 and ptr). Additional aliases are provided for convenience and + to match the types used by the C helper implementation. + + The target helper.h should be included in all files that use/define + helper functions. THis will ensure that function prototypes are + consistent. In addition it should be included an extra two times for + helper.c, defining: + GEN_HELPER 1 to produce op generation functions (gen_helper_*) + GEN_HELPER 2 to do runtime registration helper functions. + */ + +#ifndef DEF_HELPER_H +#define DEF_HELPER_H 1 + +#define HELPER(name) glue(helper_, name) + +#define GET_TCGV_i32 GET_TCGV_I32 +#define GET_TCGV_i64 GET_TCGV_I64 +#define GET_TCGV_ptr GET_TCGV_PTR + +/* Some types that make sense in C, but not for TCG. */ +#define dh_alias_i32 i32 +#define dh_alias_s32 i32 +#define dh_alias_int i32 +#define dh_alias_i64 i64 +#define dh_alias_s64 i64 +#define dh_alias_f32 i32 +#define dh_alias_f64 i64 +#if TARGET_LONG_BITS == 32 +#define dh_alias_tl i32 +#else +#define dh_alias_tl i64 +#endif +#define dh_alias_ptr ptr +#define dh_alias_void void +#define dh_alias_env ptr +#define dh_alias(t) glue(dh_alias_, t) + +#define dh_ctype_i32 uint32_t +#define dh_ctype_s32 int32_t +#define dh_ctype_int int +#define dh_ctype_i64 uint64_t +#define dh_ctype_s64 int64_t +#define dh_ctype_f32 float32 +#define dh_ctype_f64 float64 +#define dh_ctype_tl target_ulong +#define dh_ctype_ptr void * +#define dh_ctype_void void +#define dh_ctype_env CPUState * +#define dh_ctype(t) dh_ctype_##t + +/* We can't use glue() here because it falls foul of C preprocessor + recursive expansion rules. */ +#define dh_retvar_decl0_void void +#define dh_retvar_decl0_i32 TCGv_i32 retval +#define dh_retvar_decl0_i64 TCGv_i64 retval +#define dh_retvar_decl0_ptr TCGv_ptr retval +#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t)) + +#define dh_retvar_decl_void +#define dh_retvar_decl_i32 TCGv_i32 retval, +#define dh_retvar_decl_i64 TCGv_i64 retval, +#define dh_retvar_decl_ptr TCGv_ptr retval, +#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t)) + +#define dh_retvar_void TCG_CALL_DUMMY_ARG +#define dh_retvar_i32 GET_TCGV_i32(retval) +#define dh_retvar_i64 GET_TCGV_i64(retval) +#define dh_retvar_ptr GET_TCGV_ptr(retval) +#define dh_retvar(t) glue(dh_retvar_, dh_alias(t)) + +#define dh_is_64bit_void 0 +#define dh_is_64bit_i32 0 +#define dh_is_64bit_i64 1 +#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64) +#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t)) + +#define dh_arg(t, n) \ + args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \ + sizemask |= dh_is_64bit(t) << n + +#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n) + + +#define DEF_HELPER_0(name, ret) \ + DEF_HELPER_FLAGS_0(name, 0, ret) +#define DEF_HELPER_1(name, ret, t1) \ + DEF_HELPER_FLAGS_1(name, 0, ret, t1) +#define DEF_HELPER_2(name, ret, t1, t2) \ + DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2) +#define DEF_HELPER_3(name, ret, t1, t2, t3) \ + DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3) +#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \ + DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4) + +#endif /* DEF_HELPER_H */ + +#ifndef GEN_HELPER +/* Function prototypes. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +dh_ctype(ret) HELPER(name) (void); + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1)); + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)); + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3)); + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ + dh_ctype(t4)); + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == 1 +/* Gen functions. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \ +{ \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 0, NULL); \ +} + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \ +{ \ + TCGArg args[1]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \ +} + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2)) \ +{ \ + TCGArg args[2]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \ +} + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \ +{ \ + TCGArg args[3]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + dh_arg(t3, 3); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 3, args); \ +} + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \ + dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \ +{ \ + TCGArg args[4]; \ + int sizemask; \ + sizemask = dh_is_64bit(ret); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + dh_arg(t3, 3); \ + dh_arg(t4, 4); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \ +} + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == 2 +/* Register helpers. */ + +#define DEF_HELPER_FLAGS_0(name, flags, ret) \ +tcg_register_helper(HELPER(name), #name); + +#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + +#undef GEN_HELPER +#define GEN_HELPER -1 + +#elif GEN_HELPER == -1 +/* Undefine macros. */ + +#undef DEF_HELPER_FLAGS_0 +#undef DEF_HELPER_FLAGS_1 +#undef DEF_HELPER_FLAGS_2 +#undef DEF_HELPER_FLAGS_3 +#undef DEF_HELPER_FLAGS_4 +#undef GEN_HELPER + +#endif diff --git a/qemu/qemu-git/default-configs/.svn/all-wcprops b/qemu/qemu-git/default-configs/.svn/all-wcprops new file mode 100644 index 0000000..3879f89 --- /dev/null +++ b/qemu/qemu-git/default-configs/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/default-configs +END +arm-softmmu-small.mak +K 25 +svn:wc:ra_dav:version-url +V 77 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/default-configs/arm-softmmu-small.mak +END diff --git a/qemu/qemu-git/default-configs/.svn/entries b/qemu/qemu-git/default-configs/.svn/entries new file mode 100644 index 0000000..f15fedc --- /dev/null +++ b/qemu/qemu-git/default-configs/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/default-configs +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +arm-softmmu-small.mak +file + + + + +2013-08-23T00:54:47.000000Z +64ac24606b42f3ed1f3df80f11831ec2 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +62 + diff --git a/qemu/qemu-git/default-configs/.svn/text-base/arm-softmmu-small.mak.svn-base b/qemu/qemu-git/default-configs/.svn/text-base/arm-softmmu-small.mak.svn-base new file mode 100644 index 0000000..2786138 --- /dev/null +++ b/qemu/qemu-git/default-configs/.svn/text-base/arm-softmmu-small.mak.svn-base @@ -0,0 +1,3 @@ +# Default configuration for arm-softmmu + +CONFIG_GDBSTUB_XML=y diff --git a/qemu/qemu-git/default-configs/arm-softmmu-small.mak b/qemu/qemu-git/default-configs/arm-softmmu-small.mak new file mode 100644 index 0000000..2786138 --- /dev/null +++ b/qemu/qemu-git/default-configs/arm-softmmu-small.mak @@ -0,0 +1,3 @@ +# Default configuration for arm-softmmu + +CONFIG_GDBSTUB_XML=y diff --git a/qemu/qemu-git/dis-asm.h b/qemu/qemu-git/dis-asm.h new file mode 100644 index 0000000..5f6f06c --- /dev/null +++ b/qemu/qemu-git/dis-asm.h @@ -0,0 +1,477 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#include +#include +#include +#include +#include + +typedef void *PTR; +typedef uint64_t bfd_vma; +typedef int64_t bfd_signed_vma; +typedef uint8_t bfd_byte; +#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x) +#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x) + +#define BFD64 + +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_evax_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 +#define bfd_mach_cpu32 8 +#define bfd_mach_mcf5200 9 +#define bfd_mach_mcf5206e 10 +#define bfd_mach_mcf5307 11 +#define bfd_mach_mcf5407 12 +#define bfd_mach_mcf528x 13 +#define bfd_mach_mcfv4e 14 +#define bfd_mach_mcf521x 15 +#define bfd_mach_mcf5249 16 +#define bfd_mach_mcf547x 17 +#define bfd_mach_mcf548x 18 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 +/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ +#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ +/* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ + && (mach) != bfd_mach_sparc_sparclite_le) + bfd_arch_mips, /* MIPS Rxxxx */ +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips16 16 + bfd_arch_i386, /* Intel 386 */ +#define bfd_mach_i386_i386 0 +#define bfd_mach_i386_i8086 1 +#define bfd_mach_i386_i386_intel_syntax 2 +#define bfd_mach_x86_64 3 +#define bfd_mach_x86_64_intel_syntax 4 + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 +#define bfd_mach_h8300s 3 + bfd_arch_powerpc, /* PowerPC */ +#define bfd_mach_ppc 0 +#define bfd_mach_ppc64 1 +#define bfd_mach_ppc_403 403 +#define bfd_mach_ppc_403gc 4030 +#define bfd_mach_ppc_e500 500 +#define bfd_mach_ppc_505 505 +#define bfd_mach_ppc_601 601 +#define bfd_mach_ppc_602 602 +#define bfd_mach_ppc_603 603 +#define bfd_mach_ppc_ec603e 6031 +#define bfd_mach_ppc_604 604 +#define bfd_mach_ppc_620 620 +#define bfd_mach_ppc_630 630 +#define bfd_mach_ppc_750 750 +#define bfd_mach_ppc_860 860 +#define bfd_mach_ppc_a35 35 +#define bfd_mach_ppc_rs64ii 642 +#define bfd_mach_ppc_rs64iii 643 +#define bfd_mach_ppc_7400 7400 + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 + bfd_arch_d10v, /* Mitsubishi D10V */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ +#define bfd_mach_sh 1 +#define bfd_mach_sh2 0x20 +#define bfd_mach_sh_dsp 0x2d +#define bfd_mach_sh2a 0x2a +#define bfd_mach_sh2a_nofpu 0x2b +#define bfd_mach_sh2e 0x2e +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_nommu 0x31 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 +#define bfd_mach_sh4_nofpu 0x41 +#define bfd_mach_sh4_nommu_nofpu 0x42 +#define bfd_mach_sh4a 0x4a +#define bfd_mach_sh4a_nofpu 0x4b +#define bfd_mach_sh4al_dsp 0x4d +#define bfd_mach_sh5 0x50 + bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha 1 + bfd_arch_arm, /* Advanced Risc Machines ARM */ +#define bfd_mach_arm_unknown 0 +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 +#define bfd_mach_arm_ep9312 11 +#define bfd_mach_arm_iWMMXt 12 +#define bfd_mach_arm_iWMMXt2 13 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 0 + bfd_arch_arc, /* Argonaut RISC Core */ +#define bfd_mach_arc_base 0 + bfd_arch_m32r, /* Mitsubishi M32R/D */ +#define bfd_mach_m32r 0 /* backwards compatibility */ + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_cris, /* Axis CRIS */ +#define bfd_mach_cris_v0_v10 255 +#define bfd_mach_cris_v32 32 +#define bfd_mach_cris_v10_v32 1032 + bfd_arch_microblaze, /* Xilinx MicroBlaze. */ + bfd_arch_last + }; +#define bfd_mach_s390_31 31 +#define bfd_mach_s390_64 64 + +typedef struct symbol_cache_entry +{ + const char *name; + union + { + PTR p; + bfd_vma i; + } udata; +} asymbol; + +typedef int (*fprintf_ftype) (FILE*, const char*, ...); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + FILE *stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + (int status, bfd_vma memaddr, struct disassemble_info *info); + + /* Function called to print ADDR. */ + void (*print_address_func) + (bfd_vma addr, struct disassemble_info *info); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + (bfd_vma addr, struct disassemble_info * info); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *); + +extern int print_insn_big_mips (bfd_vma, disassemble_info*); +extern int print_insn_little_mips (bfd_vma, disassemble_info*); +extern int print_insn_i386 (bfd_vma, disassemble_info*); +extern int print_insn_m68k (bfd_vma, disassemble_info*); +extern int print_insn_z8001 (bfd_vma, disassemble_info*); +extern int print_insn_z8002 (bfd_vma, disassemble_info*); +extern int print_insn_h8300 (bfd_vma, disassemble_info*); +extern int print_insn_h8300h (bfd_vma, disassemble_info*); +extern int print_insn_h8300s (bfd_vma, disassemble_info*); +extern int print_insn_h8500 (bfd_vma, disassemble_info*); +extern int print_insn_alpha (bfd_vma, disassemble_info*); +extern disassembler_ftype arc_get_disassembler (int, int); +extern int print_insn_arm (bfd_vma, disassemble_info*); +extern int print_insn_sparc (bfd_vma, disassemble_info*); +extern int print_insn_big_a29k (bfd_vma, disassemble_info*); +extern int print_insn_little_a29k (bfd_vma, disassemble_info*); +extern int print_insn_i960 (bfd_vma, disassemble_info*); +extern int print_insn_sh (bfd_vma, disassemble_info*); +extern int print_insn_shl (bfd_vma, disassemble_info*); +extern int print_insn_hppa (bfd_vma, disassemble_info*); +extern int print_insn_m32r (bfd_vma, disassemble_info*); +extern int print_insn_m88k (bfd_vma, disassemble_info*); +extern int print_insn_mn10200 (bfd_vma, disassemble_info*); +extern int print_insn_mn10300 (bfd_vma, disassemble_info*); +extern int print_insn_ns32k (bfd_vma, disassemble_info*); +extern int print_insn_big_powerpc (bfd_vma, disassemble_info*); +extern int print_insn_little_powerpc (bfd_vma, disassemble_info*); +extern int print_insn_rs6000 (bfd_vma, disassemble_info*); +extern int print_insn_w65 (bfd_vma, disassemble_info*); +extern int print_insn_d10v (bfd_vma, disassemble_info*); +extern int print_insn_v850 (bfd_vma, disassemble_info*); +extern int print_insn_tic30 (bfd_vma, disassemble_info*); +extern int print_insn_ppc (bfd_vma, disassemble_info*); +extern int print_insn_s390 (bfd_vma, disassemble_info*); +extern int print_insn_crisv32 (bfd_vma, disassemble_info*); +extern int print_insn_microblaze (bfd_vma, disassemble_info*); + +#if 0 +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler (bfd *); +#endif + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + (bfd_vma, bfd_byte *, int, struct disassemble_info *); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory (int, bfd_vma, struct disassemble_info *); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address (bfd_vma, struct disassemble_info *); + +/* Always true. */ +extern int generic_symbol_at_address (bfd_vma, struct disassemble_info *); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (FPRINTF_FUNC), \ + (INFO).stream = (STREAM), \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).private_data = NULL, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).disassembler_options = NULL, \ + (INFO).insn_info_valid = 0 + +#define _(x) x +#define ATTRIBUTE_UNUSED __attribute__((unused)) + +/* from libbfd */ + +bfd_vma bfd_getl32 (const bfd_byte *addr); +bfd_vma bfd_getb32 (const bfd_byte *addr); +bfd_vma bfd_getl16 (const bfd_byte *addr); +bfd_vma bfd_getb16 (const bfd_byte *addr); +typedef bool bfd_boolean; + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/qemu/qemu-git/disas.c b/qemu/qemu-git/disas.c new file mode 100644 index 0000000..28b9398 --- /dev/null +++ b/qemu/qemu-git/disas.c @@ -0,0 +1,416 @@ +/* General "disassemble this chunk" code. Used for debugging. */ +#include "config.h" +#include "dis-asm.h" +#include "elf.h" +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +struct syminfo *syminfos = NULL; + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +static int +target_read_memory (bfd_vma memaddr, + bfd_byte *myaddr, + int length, + struct disassemble_info *info) +{ + cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (bfd_vma addr, struct disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); +} + +/* Just return the given address. */ + +int +generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) +{ + return 1; +} + +bfd_vma bfd_getl32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return (bfd_vma) v; +} + +bfd_vma bfd_getb32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return (bfd_vma) v; +} + +bfd_vma bfd_getl16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + return (bfd_vma) v; +} + +bfd_vma bfd_getb16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + return (bfd_vma) v; +} + +#ifdef TARGET_ARM +static int +print_insn_thumb1(bfd_vma pc, disassemble_info *info) +{ + return print_insn_arm(pc | 1, info); +} +#endif + +/* Disassemble this for me please... (debugging). 'flags' has the following + values: + i386 - nonzero means 16 bit code + arm - nonzero means thumb code + ppc - nonzero means little endian + other targets - unused + */ +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) +{ + target_ulong pc; + int count; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.read_memory_func = target_read_memory; + disasm_info.buffer_vma = code; + disasm_info.buffer_length = size; + +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(TARGET_I386) + if (flags == 2) + disasm_info.mach = bfd_mach_x86_64; + else if (flags == 1) + disasm_info.mach = bfd_mach_i386_i8086; + else + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + if (flags) + print_insn = print_insn_thumb1; + else + print_insn = print_insn_arm; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(TARGET_PPC) + if (flags >> 16) + disasm_info.endian = BFD_ENDIAN_LITTLE; + if (flags & 0xFFFF) { + /* If we have a precise definitions of the instructions set, use it */ + disasm_info.mach = flags & 0xFFFF; + } else { +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif + } + print_insn = print_insn_ppc; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; +#elif defined(TARGET_MIPS) +#ifdef TARGET_WORDS_BIGENDIAN + print_insn = print_insn_big_mips; +#else + print_insn = print_insn_little_mips; +#endif +#elif defined(TARGET_SH4) + disasm_info.mach = bfd_mach_sh4; + print_insn = print_insn_sh; +#elif defined(TARGET_ALPHA) + disasm_info.mach = bfd_mach_alpha; + print_insn = print_insn_alpha; +#elif defined(TARGET_CRIS) + disasm_info.mach = bfd_mach_cris_v32; + print_insn = print_insn_crisv32; +#elif defined(TARGET_MICROBLAZE) + disasm_info.mach = bfd_arch_microblaze; + print_insn = print_insn_microblaze; +#else + fprintf(out, "0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", code); + return; +#endif + + for (pc = code; size > 0; pc += count, size -= count) { + fprintf(out, "0x" TARGET_FMT_lx ": ", pc); + count = print_insn(pc, &disasm_info); +#if 0 + { + int i; + uint8_t b; + fprintf(out, " {"); + for(i = 0; i < count; i++) { + target_read_memory(pc + i, &b, 1, &disasm_info); + fprintf(out, " %02x", b); + } + fprintf(out, " }"); + } +#endif + fprintf(out, "\n"); + if (count < 0) + break; + if (size < count) { + fprintf(out, + "Disassembler disagrees with translator over instruction " + "decoding\n" + "Please report this to qemu-devel@nongnu.org\n"); + break; + } + } +} + +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size) +{ + unsigned long pc; + int count; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.buffer = code; + disasm_info.buffer_vma = (unsigned long)code; + disasm_info.buffer_length = size; + +#ifdef HOST_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(__i386__) + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(__x86_64__) + disasm_info.mach = bfd_mach_x86_64; + print_insn = print_insn_i386; +#elif defined(_ARCH_PPC) + print_insn = print_insn_ppc; +#elif defined(__alpha__) + print_insn = print_insn_alpha; +#elif defined(__sparc__) + print_insn = print_insn_sparc; +#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(__arm__) + print_insn = print_insn_arm; +#elif defined(__MIPSEB__) + print_insn = print_insn_big_mips; +#elif defined(__MIPSEL__) + print_insn = print_insn_little_mips; +#elif defined(__m68k__) + print_insn = print_insn_m68k; +#elif defined(__s390__) + print_insn = print_insn_s390; +#elif defined(__hppa__) + print_insn = print_insn_hppa; +#else + fprintf(out, "0x%lx: Asm output not supported on this arch\n", + (long) code); + return; +#endif + for (pc = (unsigned long)code; size > 0; pc += count, size -= count) { + fprintf(out, "0x%08lx: ", pc); +#ifdef __arm__ + /* since data is included in the code, it is better to + display code data too */ + fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); +#endif + count = print_insn(pc, &disasm_info); + fprintf(out, "\n"); + if (count < 0) + break; + } +} + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(target_ulong orig_addr) +{ + const char *symbol = ""; + struct syminfo *s; + + for (s = syminfos; s; s = s->next) { + symbol = s->lookup_symbol(s, orig_addr); + if (symbol[0] != '\0') { + break; + } + } + + return symbol; +} + +#ifndef X49GP +#if !defined(CONFIG_USER_ONLY) + +#include "monitor.h" + +static int monitor_disas_is_physical; +static CPUState *monitor_disas_env; + +static int +monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) +{ + if (monitor_disas_is_physical) { + cpu_physical_memory_rw(memaddr, myaddr, length, 0); + } else { + cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); + } + return 0; +} + +static int monitor_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + monitor_vprintf((Monitor *)stream, fmt, ap); + va_end(ap); + return 0; +} + +void monitor_disas(Monitor *mon, CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags) +{ + int count, i; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf); + + monitor_disas_env = env; + monitor_disas_is_physical = is_physical; + disasm_info.read_memory_func = monitor_read_memory; + + disasm_info.buffer_vma = pc; + +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(TARGET_I386) + if (flags == 2) + disasm_info.mach = bfd_mach_x86_64; + else if (flags == 1) + disasm_info.mach = bfd_mach_i386_i8086; + else + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + print_insn = print_insn_arm; +#elif defined(TARGET_ALPHA) + print_insn = print_insn_alpha; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + disasm_info.mach = bfd_mach_sparc_v9b; +#endif +#elif defined(TARGET_PPC) +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif + print_insn = print_insn_ppc; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; +#elif defined(TARGET_MIPS) +#ifdef TARGET_WORDS_BIGENDIAN + print_insn = print_insn_big_mips; +#else + print_insn = print_insn_little_mips; +#endif +#elif defined(TARGET_SH4) + disasm_info.mach = bfd_mach_sh4; + print_insn = print_insn_sh; +#else + monitor_printf(mon, "0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", pc); + return; +#endif + + for(i = 0; i < nb_insn; i++) { + monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc); + count = print_insn(pc, &disasm_info); + monitor_printf(mon, "\n"); + if (count < 0) + break; + pc += count; + } +} +#endif /* !X49GP */ +#endif diff --git a/qemu/qemu-git/disas.h b/qemu/qemu-git/disas.h new file mode 100644 index 0000000..06abab2 --- /dev/null +++ b/qemu/qemu-git/disas.h @@ -0,0 +1,41 @@ +#ifndef _QEMU_DISAS_H +#define _QEMU_DISAS_H + +#include "qemu-common.h" + +#ifdef NEED_CPU_H +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size); +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags); + +/* The usual mess... FIXME: Remove this condition once dyngen-exec.h is gone */ +#ifndef __DYNGEN_EXEC_H__ +void monitor_disas(Monitor *mon, CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags); +#endif + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(target_ulong orig_addr); +#endif + +struct syminfo; +struct elf32_sym; +struct elf64_sym; + +typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_phys_addr_t orig_addr); + +struct syminfo { + lookup_symbol_t lookup_symbol; + unsigned int disas_num_syms; + union { + struct elf32_sym *elf32; + struct elf64_sym *elf64; + } disas_symtab; + const char *disas_strtab; + struct syminfo *next; +}; + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +extern struct syminfo *syminfos; + +#endif /* _QEMU_DISAS_H */ diff --git a/qemu/qemu-git/dyngen-exec.h b/qemu/qemu-git/dyngen-exec.h new file mode 100644 index 0000000..0353f36 --- /dev/null +++ b/qemu/qemu-git/dyngen-exec.h @@ -0,0 +1,130 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#if !defined(__DYNGEN_EXEC_H__) +#define __DYNGEN_EXEC_H__ + +/* prevent Solaris from trying to typedef FILE in gcc's + include/floatingpoint.h which will conflict with the + definition down below */ +#ifdef __sun__ +#define _FILEDEFED +#endif + +/* NOTE: standard headers should be used with special care at this + point because host CPU registers are used as global variables. Some + host headers do not allow that. */ +#include +#include + +#ifdef __OpenBSD__ +#include +#endif + +/* XXX: This may be wrong for 64-bit ILP32 hosts. */ +typedef void * host_reg_t; + +#ifdef CONFIG_BSD +typedef struct __sFILE FILE; +#else +typedef struct FILE FILE; +#endif +extern int fprintf(FILE *, const char *, ...); +extern int fputs(const char *, FILE *); +extern int printf(const char *, ...); + +#if defined(__i386__) +#define AREG0 "ebp" +#define AREG1 "ebx" +#define AREG2 "esi" +#elif defined(__x86_64__) +#define AREG0 "r14" +#define AREG1 "r15" +#define AREG2 "r12" +#elif defined(_ARCH_PPC) +#define AREG0 "r27" +#define AREG1 "r24" +#define AREG2 "r25" +#elif defined(__arm__) +#define AREG0 "r7" +#define AREG1 "r4" +#define AREG2 "r5" +#elif defined(__hppa__) +#define AREG0 "r17" +#define AREG1 "r14" +#define AREG2 "r15" +#elif defined(__mips__) +#define AREG0 "fp" +#define AREG1 "s0" +#define AREG2 "s1" +#elif defined(__sparc__) +#ifdef CONFIG_SOLARIS +#define AREG0 "g2" +#define AREG1 "g3" +#define AREG2 "g4" +#else +#ifdef __sparc_v9__ +#define AREG0 "g5" +#define AREG1 "g6" +#define AREG2 "g7" +#else +#define AREG0 "g6" +#define AREG1 "g1" +#define AREG2 "g2" +#endif +#endif +#elif defined(__s390__) +#define AREG0 "r10" +#define AREG1 "r7" +#define AREG2 "r8" +#elif defined(__alpha__) +/* Note $15 is the frame pointer, so anything in op-i386.c that would + require a frame pointer, like alloca, would probably loose. */ +#define AREG0 "$15" +#define AREG1 "$9" +#define AREG2 "$10" +#elif defined(__mc68000) +#define AREG0 "%a5" +#define AREG1 "%a4" +#define AREG2 "%d7" +#elif defined(__ia64__) +#define AREG0 "r7" +#define AREG1 "r4" +#define AREG2 "r5" +#else +#error unsupported CPU +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s + +/* The return address may point to the start of the next instruction. + Subtracting one gets us the call instruction itself. */ +#if defined(__s390__) && !defined(__s390x__) +# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) +#elif defined(__arm__) +/* Thumb return addresses have the low bit set, so we need to subtract two. + This is still safe in ARM mode because instructions are 4 bytes. */ +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2)) +#else +# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1)) +#endif + +#endif /* !defined(__DYNGEN_EXEC_H__) */ diff --git a/qemu/qemu-git/elf.h b/qemu/qemu-git/elf.h new file mode 100644 index 0000000..11674d7 --- /dev/null +++ b/qemu/qemu-git/elf.h @@ -0,0 +1,1193 @@ +#ifndef _QEMU_ELF_H +#define _QEMU_ELF_H + +#include + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_OPTIONS 0x70000001 + +/* Flags in the e_flags field of the header */ +/* MIPS architecture level. */ +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ + +/* The ABI of a file. */ +#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ +#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ + +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ABI2 0x00000020 +#define EF_MIPS_OPTIONS_FIRST 0x00000080 +#define EF_MIPS_32BITMODE 0x00000100 +#define EF_MIPS_ABI 0x0000f000 +#define EF_MIPS_ARCH 0xf0000000 + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 + +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ + +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ + +#define EM_ARM 40 /* ARM */ + +#define EM_SH 42 /* SuperH */ + +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ + +#define EM_IA_64 50 /* HP/Intel IA-64 */ + +#define EM_X86_64 62 /* AMD x86-64 */ + +#define EM_S390 22 /* IBM S/390 */ + +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ + +#define EM_V850 87 /* NEC v850 */ + +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ + +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 + +/* Bogus old v850 magic number, used by old tools. */ +#define EM_CYGNUS_V850 0x9080 + +/* + * This is the old interim value for S/390 architecture + */ +#define EM_S390_OLD 0xA390 + +#define EM_XILINX_MICROBLAZE 0xBAAB + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +/* Symbolic values for the entries in the auxiliary table + put on the initial stack */ +#define AT_NULL 0 /* end of vector */ +#define AT_IGNORE 1 /* entry should be ignored */ +#define AT_EXECFD 2 /* file descriptor of program */ +#define AT_PHDR 3 /* program headers for program */ +#define AT_PHENT 4 /* size of program header entry */ +#define AT_PHNUM 5 /* number of program headers */ +#define AT_PAGESZ 6 /* system page size */ +#define AT_BASE 7 /* base address of interpreter */ +#define AT_FLAGS 8 /* flags */ +#define AT_ENTRY 9 /* entry point of program */ +#define AT_NOTELF 10 /* program is not ELF */ +#define AT_UID 11 /* real uid */ +#define AT_EUID 12 /* effective uid */ +#define AT_GID 13 /* real gid */ +#define AT_EGID 14 /* effective gid */ +#define AT_PLATFORM 15 /* string identifying CPU for optimizations */ +#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_CLKTCK 17 /* frequency at which times() increments */ + +typedef struct dynamic{ + Elf32_Sword d_tag; + union{ + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000) + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + + +/* + * Sparc ELF relocation types + */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 + +/* + * 68k ELF relocation types + */ +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 + +/* + * Alpha ELF relocation types + */ +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_BRSGP 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define SHF_ALPHA_GPREL 0x10000000 + + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#ifndef R_PPC_NUM +#define R_PPC_NUM 37 +#endif + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_NEW_ABI 0x80 +#define EF_OLD_ABI 0x100 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* s390 relocations defined by the ABIs */ +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS + block. */ +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym { + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + + +#define EI_NIDENT 16 + +typedef struct elf32_hdr{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr { + unsigned char e_ident[16]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 +#define SHF_MIPS_GPREL 0x10000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff +#define SHN_MIPS_ACCOMON 0xff00 + +typedef struct elf32_shdr { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr { + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ + + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note { + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note { + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; + +#ifdef ELF_CLASS +#if ELF_CLASS == ELFCLASS32 + +#define elfhdr elf32_hdr +#define elf_phdr elf32_phdr +#define elf_note elf32_note +#define elf_shdr elf32_shdr +#define elf_sym elf32_sym +#define elf_addr_t Elf32_Off + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf32_Rela +#else +# define ELF_RELOC Elf32_Rel +#endif + +#else + +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note +#define elf_shdr elf64_shdr +#define elf_sym elf64_sym +#define elf_addr_t Elf64_Off + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf64_Rela +#else +# define ELF_RELOC Elf64_Rel +#endif + +#endif /* ELF_CLASS */ + +#ifndef ElfW +# if ELF_CLASS == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +#endif /* ELF_CLASS */ + + +#endif /* _QEMU_ELF_H */ diff --git a/qemu/qemu-git/exec-all.h b/qemu/qemu-git/exec-all.h new file mode 100644 index 0000000..820b59e --- /dev/null +++ b/qemu/qemu-git/exec-all.h @@ -0,0 +1,360 @@ +/* + * internal execution defines for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef _EXEC_ALL_H_ +#define _EXEC_ALL_H_ + +#include "qemu-common.h" + +/* allow to see translation results - the slowdown should be negligible, so we leave it */ +#define DEBUG_DISAS + +/* is_jmp field values */ +#define DISAS_NEXT 0 /* next instruction can be analyzed */ +#define DISAS_JUMP 1 /* only pc was modified dynamically */ +#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ +#define DISAS_TB_JUMP 3 /* only pc was modified statically */ + +typedef struct TranslationBlock TranslationBlock; + +/* XXX: make safe guess about sizes */ +#define MAX_OP_PER_INSTR 96 +/* A Call op needs up to 6 + 2N parameters (N = number of arguments). */ +#define MAX_OPC_PARAM 10 +#define OPC_BUF_SIZE 640 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) + +/* Maximum size a TCG op can expand to. This is complicated because a + single op may require several host instructions and register reloads. + For now take a wild guess at 192 bytes, which should allow at least + a couple of fixup instructions per argument. */ +#define TCG_MAX_OP_SIZE 192 + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) + +extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; +extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; +extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; +extern target_ulong gen_opc_jump_pc[2]; +extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + +#include "qemu-log.h" + +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); +void gen_pc_load(CPUState *env, struct TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc); + +unsigned long code_gen_max_block_size(void); +void cpu_gen_init(void); +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, + int *gen_code_size_ptr); +int cpu_restore_state(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc); +int cpu_restore_state_copy(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc); +void cpu_resume_from_signal(CPUState *env1, void *puc); +void cpu_io_recompile(CPUState *env, void *retaddr); +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, int flags, + int cflags); +void cpu_exec_init(CPUState *env); +void QEMU_NORETURN cpu_loop_exit(void); +int page_unprotect(target_ulong address, unsigned long pc, void *puc); +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, + int is_cpu_write_access); +void tb_invalidate_page_range(target_ulong start, target_ulong end); +void tlb_flush_page(CPUState *env, target_ulong addr); +void tlb_flush(CPUState *env, int flush_global); +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu); +static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + if (prot & PAGE_READ) + prot |= PAGE_EXEC; + return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); +} + +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +#define CODE_GEN_PHYS_HASH_BITS 15 +#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) + +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) + +/* estimated block size for TB allocation */ +/* XXX: use a per code average code fragment size and modulate it + according to the host CPU */ +#if defined(CONFIG_SOFTMMU) +#define CODE_GEN_AVG_BLOCK_SIZE 128 +#else +#define CODE_GEN_AVG_BLOCK_SIZE 64 +#endif + +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) +#define USE_DIRECT_JUMP +#endif + +struct TranslationBlock { + target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ + target_ulong cs_base; /* CS base for this block */ + uint64_t flags; /* flags defining in which context the code was generated */ + uint16_t size; /* size of target code for this block (1 <= + size <= TARGET_PAGE_SIZE) */ + uint16_t cflags; /* compile flags */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ + + uint8_t *tc_ptr; /* pointer to the translated code */ + /* next matching tb for physical address. */ + struct TranslationBlock *phys_hash_next; + /* first and second physical page containing code. The lower bit + of the pointer tells the index in page_next[] */ + struct TranslationBlock *page_next[2]; + target_ulong page_addr[2]; + + /* the following data are used to directly call another TB from + the code of this one. */ + uint16_t tb_next_offset[2]; /* offset of original jump target */ +#ifdef USE_DIRECT_JUMP + uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ +#else + unsigned long tb_next[2]; /* address of jump generated code */ +#endif + /* list of TBs jumping to this one. This is a circular list using + the two least significant bits of the pointers to tell what is + the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = + jmp_first */ + struct TranslationBlock *jmp_next[2]; + struct TranslationBlock *jmp_first; + uint32_t icount; +}; + +static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; +} + +static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) + | (tmp & TB_JMP_ADDR_MASK)); +} + +static inline unsigned int tb_phys_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); +} + +TranslationBlock *tb_alloc(target_ulong pc); +void tb_free(TranslationBlock *tb); +void tb_flush(CPUState *env); +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2); +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); + +extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; +extern uint8_t *code_gen_ptr; +extern int code_gen_max_blocks; + +#if defined(USE_DIRECT_JUMP) + +#if defined(_ARCH_PPC) +extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); +#define tb_set_jmp_target1 ppc_tb_set_jmp_target +#elif defined(__i386__) || defined(__x86_64__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + /* patch the branch destination */ + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + /* no need to flush icache explicitly */ +} +#elif defined(__arm__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ +#if QEMU_GNUC_PREREQ(4, 1) + void __clear_cache(char *beg, char *end); +#else + register unsigned long _beg __asm ("a1"); + register unsigned long _end __asm ("a2"); + register unsigned long _flg __asm ("a3"); +#endif + + /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ + *(uint32_t *)jmp_addr = + (*(uint32_t *)jmp_addr & ~0xffffff) + | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); + +#if QEMU_GNUC_PREREQ(4, 1) + __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); +#else + /* flush icache */ + _beg = jmp_addr; + _end = jmp_addr + 4; + _flg = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +#endif +} +#endif + +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + unsigned long offset; + + offset = tb->tb_jmp_offset[n]; + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); + offset = tb->tb_jmp_offset[n + 2]; + if (offset != 0xffff) + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); +} + +#else + +/* set the jump target */ +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + tb->tb_next[n] = addr; +} + +#endif + +static inline void tb_add_jump(TranslationBlock *tb, int n, + TranslationBlock *tb_next) +{ + /* NOTE: this test is only needed for thread safety */ + if (!tb->jmp_next[n]) { + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_next[n] = tb_next->jmp_first; + tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); + } +} + +TranslationBlock *tb_find_pc(unsigned long pc_ptr); + +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; + +#include "qemu-lock.h" + +extern spinlock_t tb_lock; + +extern int tb_invalidated_flag; + +#if !defined(CONFIG_USER_ONLY) + +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, + void *retaddr); + +#include "softmmu_defs.h" + +#define ACCESS_TYPE (NB_MMU_MODES + 1) +#define MEMSUFFIX _code +#define env cpu_single_env + +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef ACCESS_TYPE +#undef MEMSUFFIX +#undef env + +#endif + +#if defined(CONFIG_USER_ONLY) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) +{ + return addr; +} +#else +/* NOTE: this function can trigger an exception */ +/* NOTE2: the returned address is not exactly the physical address: it + is the offset relative to phys_ram_base */ +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) +{ + int mmu_idx, page_index, pd; + void *p; + + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = cpu_mmu_index(env1); + if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != + (addr & TARGET_PAGE_MASK))) { + ldub_code(addr); + } + pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK; + if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { +#if defined(TARGET_SPARC) || defined(TARGET_MIPS) + do_unassigned_access(addr, 0, 1, 0, 4); +#else + cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); +#endif + } + p = (void *)(unsigned long)addr + + env1->tlb_table[mmu_idx][page_index].addend; + return qemu_ram_addr_from_host(p); +} + +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) + return 1; + + /* If not executing code then assume we are ok. */ + if (!env->current_tb) + return 1; + + return env->can_do_io != 0; +} +#endif + +typedef void (CPUDebugExcpHandler)(CPUState *env); + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); + +/* vl.c */ +extern int singlestep; + +#endif diff --git a/qemu/qemu-git/exec.c b/qemu/qemu-git/exec.c new file mode 100644 index 0000000..30930aa --- /dev/null +++ b/qemu/qemu-git/exec.c @@ -0,0 +1,3720 @@ +/* + * virtual page mapping and translated block handling + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "qemu-common.h" +#include "tcg.h" +#ifndef X49GP +#include "hw/hw.h" +#endif +#include "osdep.h" +#include "kvm.h" +#if defined(CONFIG_USER_ONLY) +#include +#endif + +//#define DEBUG_TB_INVALIDATE +//#define DEBUG_FLUSH +//#define DEBUG_TLB +//#define DEBUG_UNASSIGNED + +/* make various TB consistency checks */ +//#define DEBUG_TB_CHECK +//#define DEBUG_TLB_CHECK + +//#define DEBUG_IOPORT +//#define DEBUG_SUBPAGE + +#if !defined(CONFIG_USER_ONLY) +/* TB consistency checks only implemented for usermode emulation. */ +#undef DEBUG_TB_CHECK +#endif + +#define SMC_BITMAP_USE_THRESHOLD 10 + +#if defined(TARGET_SPARC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 41 +#elif defined(TARGET_SPARC) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#elif defined(TARGET_ALPHA) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#define TARGET_VIRT_ADDR_SPACE_BITS 42 +#elif defined(TARGET_PPC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_X86_64) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#elif defined(TARGET_I386) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#else +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#endif + +static TranslationBlock *tbs; +int code_gen_max_blocks; +TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; +static int nb_tbs; +/* any access to the tbs or the page table must use this lock */ +spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; + +#if defined(__arm__) || defined(__sparc_v9__) +/* The prologue must be reachable with a direct jump. ARM and Sparc64 + have limited branch ranges (possibly also PPC) so place it in a + section close to code segment. */ +#define code_gen_section \ + __attribute__((__section__(".gen_code"))) \ + __attribute__((aligned (32))) +#elif defined(_WIN32) +/* Maximum alignment for Win32 is 16. */ +#define code_gen_section \ + __attribute__((aligned (16))) +#else +#define code_gen_section \ + __attribute__((aligned (32))) +#endif + +uint8_t code_gen_prologue[1024] code_gen_section; +static uint8_t *code_gen_buffer; +static unsigned long code_gen_buffer_size; +/* threshold to flush the translated code buffer */ +static unsigned long code_gen_buffer_max_size; +uint8_t *code_gen_ptr; + +#if !defined(CONFIG_USER_ONLY) +int phys_ram_fd; +uint8_t *phys_ram_dirty; +static int in_migration; + +typedef struct RAMBlock { + uint8_t *host; + ram_addr_t offset; + ram_addr_t length; + struct RAMBlock *next; +} RAMBlock; + +static RAMBlock *ram_blocks; +/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug) + then we can no longer assume contiguous ram offsets, and external uses + of this variable will break. */ +ram_addr_t last_ram_offset; +#endif + +CPUState *first_cpu; +/* current CPU in the current thread. It is only valid inside + cpu_exec() */ +CPUState *cpu_single_env; +/* 0 = Do not count executed instructions. + 1 = Precise instruction counting. + 2 = Adaptive rate instruction counting. */ +int use_icount = 0; +/* Current instruction counter. While executing translated code this may + include some instructions that have not yet been executed. */ +int64_t qemu_icount; + +typedef struct PageDesc { + /* list of TBs intersecting this ram page */ + TranslationBlock *first_tb; + /* in order to optimize self modifying code, we count the number + of lookups we do to a given page to use a bitmap */ + unsigned int code_write_count; + uint8_t *code_bitmap; +#if defined(CONFIG_USER_ONLY) + unsigned long flags; +#endif +} PageDesc; + +typedef struct PhysPageDesc { + /* offset in host memory of the page + io_index in the low bits */ + ram_addr_t phys_offset; + ram_addr_t region_offset; +} PhysPageDesc; + +#define L2_BITS 10 +#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS) +/* XXX: this is a temporary hack for alpha target. + * In the future, this is to be replaced by a multi-level table + * to actually be able to handle the complete 64 bits address space. + */ +#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS) +#else +#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) +#endif + +#define L1_SIZE (1 << L1_BITS) +#define L2_SIZE (1 << L2_BITS) + +unsigned long qemu_real_host_page_size; +unsigned long qemu_host_page_bits; +unsigned long qemu_host_page_size; +unsigned long qemu_host_page_mask; + +/* XXX: for system emulation, it could just be an array */ +static PageDesc *l1_map[L1_SIZE]; +static PhysPageDesc **l1_phys_map; + +#if !defined(CONFIG_USER_ONLY) +static void io_mem_init(void); + +/* io memory support */ +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +void *io_mem_opaque[IO_MEM_NB_ENTRIES]; +static char io_mem_used[IO_MEM_NB_ENTRIES]; +static int io_mem_watch; +#endif + +/* log support */ +#ifdef WIN32 +static const char *logfilename = "qemu.log"; +#else +static const char *logfilename = "/tmp/qemu.log"; +#endif +FILE *logfile; +int loglevel; +static int log_append = 0; + +/* statistics */ +static int tlb_flush_count; +static int tb_flush_count; +static int tb_phys_invalidate_count; + +#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) +typedef struct subpage_t { + target_phys_addr_t base; + CPUReadMemoryFunc * const *mem_read[TARGET_PAGE_SIZE][4]; + CPUWriteMemoryFunc * const *mem_write[TARGET_PAGE_SIZE][4]; + void *opaque[TARGET_PAGE_SIZE][2][4]; + ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4]; +} subpage_t; + +#ifdef _WIN32 +static void map_exec(void *addr, long size) +{ + DWORD old_protect; + VirtualProtect(addr, size, + PAGE_EXECUTE_READWRITE, &old_protect); + +} +#else +static void map_exec(void *addr, long size) +{ + unsigned long start, end, page_size; + + page_size = getpagesize(); + start = (unsigned long)addr; + start &= ~(page_size - 1); + + end = (unsigned long)addr + size; + end += page_size - 1; + end &= ~(page_size - 1); + + mprotect((void *)start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC); +} +#endif + +static void page_init(void) +{ + /* NOTE: we can always suppose that qemu_host_page_size >= + TARGET_PAGE_SIZE */ +#ifdef _WIN32 + { + SYSTEM_INFO system_info; + + GetSystemInfo(&system_info); + qemu_real_host_page_size = system_info.dwPageSize; + } +#else + qemu_real_host_page_size = getpagesize(); +#endif + if (qemu_host_page_size == 0) + qemu_host_page_size = qemu_real_host_page_size; + if (qemu_host_page_size < TARGET_PAGE_SIZE) + qemu_host_page_size = TARGET_PAGE_SIZE; + qemu_host_page_bits = 0; + while ((1 << qemu_host_page_bits) < qemu_host_page_size) + qemu_host_page_bits++; + qemu_host_page_mask = ~(qemu_host_page_size - 1); + l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); + memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); + +#if !defined(_WIN32) && defined(CONFIG_USER_ONLY) + { + long long startaddr, endaddr; + FILE *f; + int n; + + mmap_lock(); + last_brk = (unsigned long)sbrk(0); + f = fopen("/proc/self/maps", "r"); + if (f) { + do { + n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr); + if (n == 2) { + startaddr = MIN(startaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + endaddr = MIN(endaddr, + (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1); + page_set_flags(startaddr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(endaddr), + PAGE_RESERVED); + } + } while (!feof(f)); + fclose(f); + } + mmap_unlock(); + } +#endif +} + +static inline PageDesc **page_l1_map(target_ulong index) +{ +#if TARGET_LONG_BITS > 32 + /* Host memory outside guest VM. For 32-bit targets we have already + excluded high addresses. */ + if (index > ((target_ulong)L2_SIZE * L1_SIZE)) + return NULL; +#endif + return &l1_map[index >> L2_BITS]; +} + +static inline PageDesc *page_find_alloc(target_ulong index) +{ + PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; + + p = *lp; + if (!p) { + /* allocate if not found */ +#if defined(CONFIG_USER_ONLY) + size_t len = sizeof(PageDesc) * L2_SIZE; + /* Don't use qemu_malloc because it may recurse. */ + p = mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + *lp = p; + if (h2g_valid(p)) { + unsigned long addr = h2g(p); + page_set_flags(addr & TARGET_PAGE_MASK, + TARGET_PAGE_ALIGN(addr + len), + PAGE_RESERVED); + } +#else + p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE); + *lp = p; +#endif + } + return p + (index & (L2_SIZE - 1)); +} + +static inline PageDesc *page_find(target_ulong index) +{ + PageDesc **lp, *p; + lp = page_l1_map(index); + if (!lp) + return NULL; + + p = *lp; + if (!p) { + return NULL; + } + return p + (index & (L2_SIZE - 1)); +} + +static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc) +{ + void **lp, **p; + PhysPageDesc *pd; + + p = (void **)l1_phys_map; +#if TARGET_PHYS_ADDR_SPACE_BITS > 32 + +#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS) +#error unsupported TARGET_PHYS_ADDR_SPACE_BITS +#endif + lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1)); + p = *lp; + if (!p) { + /* allocate if not found */ + if (!alloc) + return NULL; + p = qemu_vmalloc(sizeof(void *) * L1_SIZE); + memset(p, 0, sizeof(void *) * L1_SIZE); + *lp = p; + } +#endif + lp = p + ((index >> L2_BITS) & (L1_SIZE - 1)); + pd = *lp; + if (!pd) { + int i; + /* allocate if not found */ + if (!alloc) + return NULL; + pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); + *lp = pd; + for (i = 0; i < L2_SIZE; i++) { + pd[i].phys_offset = IO_MEM_UNASSIGNED; + pd[i].region_offset = (index + i) << TARGET_PAGE_BITS; + } + } + return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1)); +} + +static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) +{ + return phys_page_find_alloc(index, 0); +} + +#if !defined(CONFIG_USER_ONLY) +static void tlb_protect_code(ram_addr_t ram_addr); +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr); +#define mmap_lock() do { } while(0) +#define mmap_unlock() do { } while(0) +#endif + +#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024) + +#if defined(CONFIG_USER_ONLY) +/* Currently it is not recommended to allocate big chunks of data in + user mode. It will change when a dedicated libc will be used */ +#define USE_STATIC_CODE_GEN_BUFFER +#endif + +#ifdef USE_STATIC_CODE_GEN_BUFFER +static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]; +#endif + +static void code_gen_alloc(unsigned long tb_size) +{ +#ifdef USE_STATIC_CODE_GEN_BUFFER + code_gen_buffer = static_code_gen_buffer; + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + map_exec(code_gen_buffer, code_gen_buffer_size); +#else + code_gen_buffer_size = tb_size; + if (code_gen_buffer_size == 0) { +#if defined(CONFIG_USER_ONLY) + /* in user mode, phys_ram_size is not meaningful */ + code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; +#else + /* XXX: needs adjustments */ + code_gen_buffer_size = (unsigned long)(ram_size / 4); +#endif + } + if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) + code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; + /* The code gen buffer location may have constraints depending on + the host cpu and OS */ +#if defined(__linux__) + { + int flags; + void *start = NULL; + + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + flags |= MAP_32BIT; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#elif defined(__sparc_v9__) + // Map the buffer below 2G, so we can use direct calls and branches + flags |= MAP_FIXED; + start = (void *) 0x60000000UL; + if (code_gen_buffer_size > (512 * 1024 * 1024)) + code_gen_buffer_size = (512 * 1024 * 1024); +#elif defined(__arm__) + /* Map the buffer below 32M, so we can use direct calls and branches */ + flags |= MAP_FIXED; + start = (void *) 0x01000000UL; + if (code_gen_buffer_size > 16 * 1024 * 1024) + code_gen_buffer_size = 16 * 1024 * 1024; +#endif + code_gen_buffer = mmap(start, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + { + int flags; + void *addr = NULL; + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume + * 0x40000000 is free */ + flags |= MAP_FIXED; + addr = (void *)0x40000000; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#endif + code_gen_buffer = mmap(addr, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#else + code_gen_buffer = qemu_malloc(code_gen_buffer_size); + map_exec(code_gen_buffer, code_gen_buffer_size); +#endif +#endif /* !USE_STATIC_CODE_GEN_BUFFER */ + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); + code_gen_buffer_max_size = code_gen_buffer_size - + code_gen_max_block_size(); + code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; + tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); +} + +/* Must be called before using the QEMU cpus. 'tb_size' is the size + (in bytes) allocated to the translation buffer. Zero means default + size. */ +void cpu_exec_init_all(unsigned long tb_size) +{ + cpu_gen_init(); + code_gen_alloc(tb_size); + code_gen_ptr = code_gen_buffer; + page_init(); +#if !defined(CONFIG_USER_ONLY) + io_mem_init(); +#endif +} + +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + +static void cpu_common_pre_save(void *opaque) +{ + CPUState *env = opaque; + + cpu_synchronize_state(env); +} + +static int cpu_common_pre_load(void *opaque) +{ + CPUState *env = opaque; + + cpu_synchronize_state(env); + return 0; +} + +static int cpu_common_post_load(void *opaque, int version_id) +{ + CPUState *env = opaque; + + /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the + version_id is increased. */ + env->interrupt_request &= ~0x01; + tlb_flush(env, 1); + + return 0; +} + +static const VMStateDescription vmstate_cpu_common = { + .name = "cpu_common", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = cpu_common_pre_save, + .pre_load = cpu_common_pre_load, + .post_load = cpu_common_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(halted, CPUState), + VMSTATE_UINT32(interrupt_request, CPUState), + VMSTATE_END_OF_LIST() + } +}; +#endif + +CPUState *qemu_get_cpu(int cpu) +{ + CPUState *env = first_cpu; + + while (env) { + if (env->cpu_index == cpu) + break; + env = env->next_cpu; + } + + return env; +} + +void cpu_exec_init(CPUState *env) +{ + CPUState **penv; + int cpu_index; + +#if defined(CONFIG_USER_ONLY) + cpu_list_lock(); +#endif + env->next_cpu = NULL; + penv = &first_cpu; + cpu_index = 0; + while (*penv != NULL) { + penv = &(*penv)->next_cpu; + cpu_index++; + } + env->cpu_index = cpu_index; + env->numa_node = 0; + QTAILQ_INIT(&env->breakpoints); + QTAILQ_INIT(&env->watchpoints); + *penv = env; +#if defined(CONFIG_USER_ONLY) + cpu_list_unlock(); +#endif +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) + vmstate_register(cpu_index, &vmstate_cpu_common, env); + register_savevm("cpu", cpu_index, CPU_SAVE_VERSION, + cpu_save, cpu_load, env); +#endif +} + +static inline void invalidate_page_bitmap(PageDesc *p) +{ + if (p->code_bitmap) { + qemu_free(p->code_bitmap); + p->code_bitmap = NULL; + } + p->code_write_count = 0; +} + +/* set to NULL all the 'first_tb' fields in all PageDescs */ +static void page_flush_tb(void) +{ + int i, j; + PageDesc *p; + + for(i = 0; i < L1_SIZE; i++) { + p = l1_map[i]; + if (p) { + for(j = 0; j < L2_SIZE; j++) { + p->first_tb = NULL; + invalidate_page_bitmap(p); + p++; + } + } + } +} + +/* flush all the translation blocks */ +/* XXX: tb_flush is currently not thread safe */ +void tb_flush(CPUState *env1) +{ + CPUState *env; +#if defined(DEBUG_FLUSH) + printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", + (unsigned long)(code_gen_ptr - code_gen_buffer), + nb_tbs, nb_tbs > 0 ? + ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); +#endif + if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size) + cpu_abort(env1, "Internal error: code buffer overflow\n"); + + nb_tbs = 0; + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + } + + memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); + page_flush_tb(); + + code_gen_ptr = code_gen_buffer; + /* XXX: flush processor icache at this point if cache flush is + expensive */ + tb_flush_count++; +} + +#ifdef DEBUG_TB_CHECK + +static void tb_invalidate_check(target_ulong address) +{ + TranslationBlock *tb; + int i; + address &= TARGET_PAGE_MASK; + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + if (!(address + TARGET_PAGE_SIZE <= tb->pc || + address >= tb->pc + tb->size)) { + printf("ERROR invalidate: address=" TARGET_FMT_lx + " PC=%08lx size=%04x\n", + address, (long)tb->pc, tb->size); + } + } + } +} + +/* verify that all the pages have correct rights for code */ +static void tb_page_check(void) +{ + TranslationBlock *tb; + int i, flags1, flags2; + + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + flags1 = page_get_flags(tb->pc); + flags2 = page_get_flags(tb->pc + tb->size - 1); + if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { + printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", + (long)tb->pc, tb->size, flags1, flags2); + } + } + } +} + +#endif + +/* invalidate one TB */ +static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, + int next_offset) +{ + TranslationBlock *tb1; + for(;;) { + tb1 = *ptb; + if (tb1 == tb) { + *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); + break; + } + ptb = (TranslationBlock **)((char *)tb1 + next_offset); + } +} + +static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) +{ + TranslationBlock *tb1; + unsigned int n1; + + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (tb1 == tb) { + *ptb = tb1->page_next[n1]; + break; + } + ptb = &tb1->page_next[n1]; + } +} + +static inline void tb_jmp_remove(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, **ptb; + unsigned int n1; + + ptb = &tb->jmp_next[n]; + tb1 = *ptb; + if (tb1) { + /* find tb(n) in circular list */ + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + if (n1 == 2) { + ptb = &tb1->jmp_first; + } else { + ptb = &tb1->jmp_next[n1]; + } + } + /* now we can suppress tb(n) from the list */ + *ptb = tb->jmp_next[n]; + + tb->jmp_next[n] = NULL; + } +} + +/* reset the jump entry 'n' of a TB so that it is not chained to + another TB */ +static inline void tb_reset_jump(TranslationBlock *tb, int n) +{ + tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); +} + +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) +{ + CPUState *env; + PageDesc *p; + unsigned int h, n1; + target_phys_addr_t phys_pc; + TranslationBlock *tb1, *tb2; + + /* remove the TB from the hash list */ + phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + h = tb_phys_hash_func(phys_pc); + tb_remove(&tb_phys_hash[h], tb, + offsetof(TranslationBlock, phys_hash_next)); + + /* remove the TB from the page list */ + if (tb->page_addr[0] != page_addr) { + p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { + p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + + tb_invalidated_flag = 1; + + /* remove the TB from the hash list */ + h = tb_jmp_cache_hash_func(tb->pc); + for(env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->tb_jmp_cache[h] == tb) + env->tb_jmp_cache[h] = NULL; + } + + /* suppress this TB from the two jump lists */ + tb_jmp_remove(tb, 0); + tb_jmp_remove(tb, 1); + + /* suppress any remaining jumps to this TB */ + tb1 = tb->jmp_first; + for(;;) { + n1 = (long)tb1 & 3; + if (n1 == 2) + break; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + tb2 = tb1->jmp_next[n1]; + tb_reset_jump(tb1, n1); + tb1->jmp_next[n1] = NULL; + tb1 = tb2; + } + tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ + + tb_phys_invalidate_count++; +} + +static inline void set_bits(uint8_t *tab, int start, int len) +{ + int end, mask, end1; + + end = start + len; + tab += start >> 3; + mask = 0xff << (start & 7); + if ((start & ~7) == (end & ~7)) { + if (start < end) { + mask &= ~(0xff << (end & 7)); + *tab |= mask; + } + } else { + *tab++ |= mask; + start = (start + 8) & ~7; + end1 = end & ~7; + while (start < end1) { + *tab++ = 0xff; + start += 8; + } + if (start < end) { + mask = ~(0xff << (end & 7)); + *tab |= mask; + } + } +} + +static void build_page_bitmap(PageDesc *p) +{ + int n, tb_start, tb_end; + TranslationBlock *tb; + + p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8); + + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->pc & ~TARGET_PAGE_MASK; + tb_end = tb_start + tb->size; + if (tb_end > TARGET_PAGE_SIZE) + tb_end = TARGET_PAGE_SIZE; + } else { + tb_start = 0; + tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + set_bits(p->code_bitmap, tb_start, tb_end - tb_start); + tb = tb->page_next[n]; + } +} + +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, + int flags, int cflags) +{ + TranslationBlock *tb; + uint8_t *tc_ptr; + target_ulong phys_pc, phys_page2, virt_page2; + int code_gen_size; + + phys_pc = get_phys_addr_code(env, pc); + tb = tb_alloc(pc); + if (!tb) { + /* flush must be done */ + tb_flush(env); + /* cannot fail at this point */ + tb = tb_alloc(pc); + /* Don't forget to invalidate previous TB info. */ + tb_invalidated_flag = 1; + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags; + cpu_gen_code(env, tb, &code_gen_size); + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + + /* check next page if needed */ + virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; + phys_page2 = -1; + if ((pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_phys_addr_code(env, virt_page2); + } + tb_link_phys(tb, phys_pc, phys_page2); + return tb; +} + +/* invalidate all TBs which intersect with the target physical page + starting in range [start;end[. NOTE: start and end must refer to + the same physical page. 'is_cpu_write_access' should be true if called + from a real cpu write access: the virtual CPU will exit the current + TB if code is modified inside this TB. */ +void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, + int is_cpu_write_access) +{ + TranslationBlock *tb, *tb_next, *saved_tb; + CPUState *env = cpu_single_env; + target_ulong tb_start, tb_end; + PageDesc *p; + int n; +#ifdef TARGET_HAS_PRECISE_SMC + int current_tb_not_found = is_cpu_write_access; + TranslationBlock *current_tb = NULL; + int current_tb_modified = 0; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; +#endif /* TARGET_HAS_PRECISE_SMC */ + + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (!p->code_bitmap && + ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && + is_cpu_write_access) { + /* build code bitmap */ + build_page_bitmap(p); + } + + /* we remove all the TBs in the range [start, end[ */ + /* XXX: see if in some cases it could be faster to invalidate all the code */ + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + tb_next = tb->page_next[n]; + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + tb_end = tb_start + tb->size; + } else { + tb_start = tb->page_addr[1]; + tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + if (!(tb_end <= start || tb_start >= end)) { +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_not_found) { + current_tb_not_found = 0; + current_tb = NULL; + if (env->mem_io_pc) { + /* now we have a real cpu fault */ + current_tb = tb_find_pc(env->mem_io_pc); + } + } + if (current_tb == tb && + (current_tb->cflags & CF_COUNT_MASK) != 1) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, + env->mem_io_pc, NULL); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } +#endif /* TARGET_HAS_PRECISE_SMC */ + /* we need to do that to handle the case where a signal + occurs while doing tb_phys_invalidate() */ + saved_tb = NULL; + if (env) { + saved_tb = env->current_tb; + env->current_tb = NULL; + } + tb_phys_invalidate(tb, -1); + if (env) { + env->current_tb = saved_tb; + if (env->interrupt_request && env->current_tb) + cpu_interrupt(env, env->interrupt_request); + } + } + tb = tb_next; + } +#if !defined(CONFIG_USER_ONLY) + /* if no code remaining, no need to continue to use slow writes */ + if (!p->first_tb) { + invalidate_page_bitmap(p); + if (is_cpu_write_access) { + tlb_unprotect_code_phys(env, start, env->mem_io_vaddr); + } + } +#endif +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + env->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, NULL); + } +#endif +} + +/* len must be <= 8 and start must be a multiple of len */ +static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len) +{ + PageDesc *p; + int offset, b; +#if 0 + if (1) { + qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n", + cpu_single_env->mem_io_vaddr, len, + cpu_single_env->eip, + cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); + } +#endif + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (p->code_bitmap) { + offset = start & ~TARGET_PAGE_MASK; + b = p->code_bitmap[offset >> 3] >> (offset & 7); + if (b & ((1 << len) - 1)) + goto do_invalidate; + } else { + do_invalidate: + tb_invalidate_phys_page_range(start, start + len, 1); + } +} + +#if !defined(CONFIG_SOFTMMU) +static void tb_invalidate_phys_page(target_phys_addr_t addr, + unsigned long pc, void *puc) +{ + TranslationBlock *tb; + PageDesc *p; + int n; +#ifdef TARGET_HAS_PRECISE_SMC + TranslationBlock *current_tb = NULL; + CPUState *env = cpu_single_env; + int current_tb_modified = 0; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; +#endif + + addr &= TARGET_PAGE_MASK; + p = page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return; + tb = p->first_tb; +#ifdef TARGET_HAS_PRECISE_SMC + if (tb && pc != 0) { + current_tb = tb_find_pc(pc); + } +#endif + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb == tb && + (current_tb->cflags & CF_COUNT_MASK) != 1) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, pc, puc); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } +#endif /* TARGET_HAS_PRECISE_SMC */ + tb_phys_invalidate(tb, addr); + tb = tb->page_next[n]; + } + p->first_tb = NULL; +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + env->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, puc); + } +#endif +} +#endif + +/* add the tb in the target page and protect it if necessary */ +static inline void tb_alloc_page(TranslationBlock *tb, + unsigned int n, target_ulong page_addr) +{ + PageDesc *p; + TranslationBlock *last_first_tb; + + tb->page_addr[n] = page_addr; + p = page_find_alloc(page_addr >> TARGET_PAGE_BITS); + tb->page_next[n] = p->first_tb; + last_first_tb = p->first_tb; + p->first_tb = (TranslationBlock *)((long)tb | n); + invalidate_page_bitmap(p); + +#if defined(TARGET_HAS_SMC) || 1 + +#if defined(CONFIG_USER_ONLY) + if (p->flags & PAGE_WRITE) { + target_ulong addr; + PageDesc *p2; + int prot; + + /* force the host page as non writable (writes will have a + page fault + mprotect overhead) */ + page_addr &= qemu_host_page_mask; + prot = 0; + for(addr = page_addr; addr < page_addr + qemu_host_page_size; + addr += TARGET_PAGE_SIZE) { + + p2 = page_find (addr >> TARGET_PAGE_BITS); + if (!p2) + continue; + prot |= p2->flags; + p2->flags &= ~PAGE_WRITE; + page_get_flags(addr); + } + mprotect(g2h(page_addr), qemu_host_page_size, + (prot & PAGE_BITS) & ~PAGE_WRITE); +#ifdef DEBUG_TB_INVALIDATE + printf("protecting code page: 0x" TARGET_FMT_lx "\n", + page_addr); +#endif + } +#else + /* if some code is already present, then the pages are already + protected. So we handle the case where only the first TB is + allocated in a physical page */ + if (!last_first_tb) { + tlb_protect_code(page_addr); + } +#endif + +#endif /* TARGET_HAS_SMC */ +} + +/* Allocate a new translation block. Flush the translation buffer if + too many translation blocks or too much generated code. */ +TranslationBlock *tb_alloc(target_ulong pc) +{ + TranslationBlock *tb; + + if (nb_tbs >= code_gen_max_blocks || + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) + return NULL; + tb = &tbs[nb_tbs++]; + tb->pc = pc; + tb->cflags = 0; + return tb; +} + +void tb_free(TranslationBlock *tb) +{ + /* In practice this is mostly used for single use temporary TB + Ignore the hard cases and just back up if this TB happens to + be the last one generated. */ + if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { + code_gen_ptr = tb->tc_ptr; + nb_tbs--; + } +} + +/* add a new TB and link it to the physical page tables. phys_page2 is + (-1) to indicate that only one page contains the TB. */ +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2) +{ + unsigned int h; + TranslationBlock **ptb; + + /* Grab the mmap lock to stop another thread invalidating this TB + before we are done. */ + mmap_lock(); + /* add in the physical hash table */ + h = tb_phys_hash_func(phys_pc); + ptb = &tb_phys_hash[h]; + tb->phys_hash_next = *ptb; + *ptb = tb; + + /* add in the page list */ + tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK); + if (phys_page2 != -1) + tb_alloc_page(tb, 1, phys_page2); + else + tb->page_addr[1] = -1; + + tb->jmp_first = (TranslationBlock *)((long)tb | 2); + tb->jmp_next[0] = NULL; + tb->jmp_next[1] = NULL; + + /* init original jump addresses */ + if (tb->tb_next_offset[0] != 0xffff) + tb_reset_jump(tb, 0); + if (tb->tb_next_offset[1] != 0xffff) + tb_reset_jump(tb, 1); + +#ifdef DEBUG_TB_CHECK + tb_page_check(); +#endif + mmap_unlock(); +} + +/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < + tb[1].tc_ptr. Return NULL if not found */ +TranslationBlock *tb_find_pc(unsigned long tc_ptr) +{ + int m_min, m_max, m; + unsigned long v; + TranslationBlock *tb; + + if (nb_tbs <= 0) + return NULL; + if (tc_ptr < (unsigned long)code_gen_buffer || + tc_ptr >= (unsigned long)code_gen_ptr) + return NULL; + /* binary search (cf Knuth) */ + m_min = 0; + m_max = nb_tbs - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + tb = &tbs[m]; + v = (unsigned long)tb->tc_ptr; + if (v == tc_ptr) + return tb; + else if (tc_ptr < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return &tbs[m_max]; +} + +static void tb_reset_jump_recursive(TranslationBlock *tb); + +static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, *tb_next, **ptb; + unsigned int n1; + + tb1 = tb->jmp_next[n]; + if (tb1 != NULL) { + /* find head of list */ + for(;;) { + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == 2) + break; + tb1 = tb1->jmp_next[n1]; + } + /* we are now sure now that tb jumps to tb1 */ + tb_next = tb1; + + /* remove tb from the jmp_first list */ + ptb = &tb_next->jmp_first; + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + ptb = &tb1->jmp_next[n1]; + } + *ptb = tb->jmp_next[n]; + tb->jmp_next[n] = NULL; + + /* suppress the jump to next tb in generated code */ + tb_reset_jump(tb, n); + + /* suppress jumps in the tb on which we could have jumped */ + tb_reset_jump_recursive(tb_next); + } +} + +static void tb_reset_jump_recursive(TranslationBlock *tb) +{ + tb_reset_jump_recursive2(tb, 0); + tb_reset_jump_recursive2(tb, 1); +} + +#if defined(TARGET_HAS_ICE) +static void breakpoint_invalidate(CPUState *env, target_ulong pc) +{ + target_phys_addr_t addr; + target_ulong pd; + ram_addr_t ram_addr; + PhysPageDesc *p; + + addr = cpu_get_phys_page_debug(env, pc); + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK); + tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); +} +#endif + +/* Add a watchpoint. */ +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint) +{ + target_ulong len_mask = ~(len - 1); + CPUWatchpoint *wp; + + /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */ + if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) { + fprintf(stderr, "qemu: tried to set invalid watchpoint at " + TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len); + return -EINVAL; + } + wp = qemu_malloc(sizeof(*wp)); + + wp->vaddr = addr; + wp->len_mask = len_mask; + wp->flags = flags; + + /* keep all GDB-injected watchpoints in front */ + if (flags & BP_GDB) + QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry); + else + QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry); + + tlb_flush_page(env, addr); + + if (watchpoint) + *watchpoint = wp; + return 0; +} + +/* Remove a specific watchpoint. */ +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len, + int flags) +{ + target_ulong len_mask = ~(len - 1); + CPUWatchpoint *wp; + + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if (addr == wp->vaddr && len_mask == wp->len_mask + && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) { + cpu_watchpoint_remove_by_ref(env, wp); + return 0; + } + } + return -ENOENT; +} + +/* Remove a specific watchpoint by reference. */ +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint) +{ + QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry); + + tlb_flush_page(env, watchpoint->vaddr); + + qemu_free(watchpoint); +} + +/* Remove all matching watchpoints. */ +void cpu_watchpoint_remove_all(CPUState *env, int mask) +{ + CPUWatchpoint *wp, *next; + + QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) { + if (wp->flags & mask) + cpu_watchpoint_remove_by_ref(env, wp); + } +} + +/* Add a breakpoint. */ +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + bp = qemu_malloc(sizeof(*bp)); + + bp->pc = pc; + bp->flags = flags; + + /* keep all GDB-injected breakpoints in front */ + if (flags & BP_GDB) + QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry); + else + QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry); + + breakpoint_invalidate(env, pc); + + if (breakpoint) + *breakpoint = bp; + return 0; +#else + return -ENOSYS; +#endif +} + +/* Remove a specific breakpoint. */ +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == pc && bp->flags == flags) { + cpu_breakpoint_remove_by_ref(env, bp); + return 0; + } + } + return -ENOENT; +#else + return -ENOSYS; +#endif +} + +/* Remove a specific breakpoint by reference. */ +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint) +{ +#if defined(TARGET_HAS_ICE) + QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry); + + breakpoint_invalidate(env, breakpoint->pc); + + qemu_free(breakpoint); +#endif +} + +/* Remove all matching breakpoints. */ +void cpu_breakpoint_remove_all(CPUState *env, int mask) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp, *next; + + QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) { + if (bp->flags & mask) + cpu_breakpoint_remove_by_ref(env, bp); + } +#endif +} + +/* enable or disable single step mode. EXCP_DEBUG is returned by the + CPU loop after each instruction */ +void cpu_single_step(CPUState *env, int enabled) +{ +#if defined(TARGET_HAS_ICE) + if (env->singlestep_enabled != enabled) { + env->singlestep_enabled = enabled; + if (kvm_enabled()) + kvm_update_guest_debug(env, 0); + else { + /* must flush all the translated code to avoid inconsistencies */ + /* XXX: only flush what is necessary */ + tb_flush(env); + } + } +#endif +} + +/* enable or disable low levels log */ +void cpu_set_log(int log_flags) +{ + loglevel = log_flags; + if (loglevel && !logfile) { + logfile = fopen(logfilename, log_append ? "a" : "w"); + if (!logfile) { + perror(logfilename); + _exit(1); + } +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static char logfile_buf[4096]; + setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); + } +#elif !defined(_WIN32) + /* Win32 doesn't support line-buffering and requires size >= 2 */ + setvbuf(logfile, NULL, _IOLBF, 0); +#endif + log_append = 1; + } + if (!loglevel && logfile) { + fclose(logfile); + logfile = NULL; + } +} + +void cpu_set_log_filename(const char *filename) +{ + logfilename = strdup(filename); + if (logfile) { + fclose(logfile); + logfile = NULL; + } + cpu_set_log(loglevel); +} + +static void cpu_unlink_tb(CPUState *env) +{ + /* FIXME: TB unchaining isn't SMP safe. For now just ignore the + problem and hope the cpu will stop of its own accord. For userspace + emulation this often isn't actually as bad as it sounds. Often + signals are used primarily to interrupt blocking syscalls. */ + TranslationBlock *tb; + static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; + + tb = env->current_tb; + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + if (tb) { + spin_lock(&interrupt_lock); + env->current_tb = NULL; + tb_reset_jump_recursive(tb); + spin_unlock(&interrupt_lock); + } +} + +/* mask must never be zero, except for A20 change call */ +void cpu_interrupt(CPUState *env, int mask) +{ + int old_mask; + + old_mask = env->interrupt_request; + env->interrupt_request |= mask; + +#ifndef CONFIG_USER_ONLY + /* + * If called from iothread context, wake the target cpu in + * case its halted. + */ + if (!qemu_cpu_self(env)) { + qemu_cpu_kick(env); + return; + } +#endif + + if (use_icount) { + env->icount_decr.u16.high = 0xffff; +#ifndef CONFIG_USER_ONLY + if (!can_do_io(env) + && (mask & ~old_mask) != 0) { + cpu_abort(env, "Raised interrupt while not in I/O function"); + } +#endif + } else { + cpu_unlink_tb(env); + } +} + +void cpu_reset_interrupt(CPUState *env, int mask) +{ + env->interrupt_request &= ~mask; +} + +void cpu_exit(CPUState *env) +{ + env->exit_request = 1; + cpu_unlink_tb(env); +} + +const CPULogItem cpu_log_items[] = { + { CPU_LOG_TB_OUT_ASM, "out_asm", + "show generated host assembly code for each compiled TB" }, + { CPU_LOG_TB_IN_ASM, "in_asm", + "show target assembly code for each compiled TB" }, + { CPU_LOG_TB_OP, "op", + "show micro ops for each compiled TB" }, + { CPU_LOG_TB_OP_OPT, "op_opt", + "show micro ops " +#ifdef TARGET_I386 + "before eflags optimization and " +#endif + "after liveness analysis" }, + { CPU_LOG_INT, "int", + "show interrupts/exceptions in short format" }, + { CPU_LOG_EXEC, "exec", + "show trace before each executed TB (lots of logs)" }, + { CPU_LOG_TB_CPU, "cpu", + "show CPU state before block translation" }, +#ifdef TARGET_I386 + { CPU_LOG_PCALL, "pcall", + "show protected mode far calls/returns/exceptions" }, + { CPU_LOG_RESET, "cpu_reset", + "show CPU state before CPU resets" }, +#endif +#ifdef DEBUG_IOPORT + { CPU_LOG_IOPORT, "ioport", + "show all i/o ports accesses" }, +#endif + { 0, NULL, NULL }, +}; + +static int cmp1(const char *s1, int n, const char *s2) +{ + if (strlen(s2) != n) + return 0; + return memcmp(s1, s2, n) == 0; +} + +/* takes a comma separated list of log masks. Return 0 if error. */ +int cpu_str_to_log_mask(const char *str) +{ + const CPULogItem *item; + int mask; + const char *p, *p1; + + p = str; + mask = 0; + for(;;) { + p1 = strchr(p, ','); + if (!p1) + p1 = p + strlen(p); + if(cmp1(p,p1-p,"all")) { + for(item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { + for(item = cpu_log_items; item->mask != 0; item++) { + if (cmp1(p, p1 - p, item->name)) + goto found; + } + return 0; + } + found: + mask |= item->mask; + if (*p1 != ',') + break; + p = p1 + 1; + } + return mask; +} + +void cpu_abort(CPUState *env, const char *fmt, ...) +{ + va_list ap; + va_list ap2; + + va_start(ap, fmt); + va_copy(ap2, ap); + fprintf(stderr, "qemu: fatal: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +#ifdef TARGET_I386 + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(env, stderr, fprintf, 0); +#endif + if (qemu_log_enabled()) { + qemu_log("qemu: fatal: "); + qemu_log_vprintf(fmt, ap2); + qemu_log("\n"); +#ifdef TARGET_I386 + log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + log_cpu_state(env, 0); +#endif + qemu_log_flush(); + qemu_log_close(); + } + va_end(ap2); + va_end(ap); + abort(); +} + +CPUState *cpu_copy(CPUState *env) +{ + CPUState *new_env = cpu_init(env->cpu_model_str); + CPUState *next_cpu = new_env->next_cpu; + int cpu_index = new_env->cpu_index; +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + CPUWatchpoint *wp; +#endif + + memcpy(new_env, env, sizeof(CPUState)); + + /* Preserve chaining and index. */ + new_env->next_cpu = next_cpu; + new_env->cpu_index = cpu_index; + + /* Clone all break/watchpoints. + Note: Once we support ptrace with hw-debug register access, make sure + BP_CPU break/watchpoints are handled correctly on clone. */ + QTAILQ_INIT(&env->breakpoints); + QTAILQ_INIT(&env->watchpoints); +#if defined(TARGET_HAS_ICE) + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL); + } + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1, + wp->flags, NULL); + } +#endif + + return new_env; +} + +#if !defined(CONFIG_USER_ONLY) + +static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr) +{ + unsigned int i; + + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); + + i = tb_jmp_cache_hash_page(addr); + memset (&env->tb_jmp_cache[i], 0, + TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); +} + +static CPUTLBEntry s_cputlb_empty_entry = { + .addr_read = -1, + .addr_write = -1, + .addr_code = -1, + .addend = -1, +}; + +/* NOTE: if flush_global is true, also flush global entries (not + implemented yet) */ +void tlb_flush(CPUState *env, int flush_global) +{ + int i; + +#if defined(DEBUG_TLB) + printf("tlb_flush:\n"); +#endif + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + + for(i = 0; i < CPU_TLB_SIZE; i++) { + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + env->tlb_table[mmu_idx][i] = s_cputlb_empty_entry; + } + } + + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + + tlb_flush_count++; +} + +static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) +{ + if (addr == (tlb_entry->addr_read & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_write & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_code & + (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + *tlb_entry = s_cputlb_empty_entry; + } +} + +void tlb_flush_page(CPUState *env, target_ulong addr) +{ + int i; + int mmu_idx; + +#if defined(DEBUG_TLB) + printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); +#endif + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + + addr &= TARGET_PAGE_MASK; + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr); + + tlb_flush_jmp_cache(env, addr); +} + +/* update the TLBs so that writes to code in the virtual page 'addr' + can be detected */ +static void tlb_protect_code(ram_addr_t ram_addr) +{ + cpu_physical_memory_reset_dirty(ram_addr, + ram_addr + TARGET_PAGE_SIZE, + CODE_DIRTY_FLAG); +} + +/* update the TLB so that writes in physical page 'phys_addr' are no longer + tested for self modifying code */ +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr) +{ + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG; +} + +static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, + unsigned long start, unsigned long length) +{ + unsigned long addr; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((addr - start) < length) { + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY; + } + } +} + +/* Note: start and end must be within the same ram block. */ +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags) +{ + CPUState *env; + unsigned long length, start1; + int i, mask, len; + uint8_t *p; + + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + + length = end - start; + if (length == 0) + return; + len = length >> TARGET_PAGE_BITS; + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + for(i = 0; i < len; i++) + p[i] &= mask; + + /* we modify the TLB cache so that the dirty bit will be set again + when accessing the range */ + start1 = (unsigned long)qemu_get_ram_ptr(start); + /* Chek that we don't span multiple blocks - this breaks the + address comparisons below. */ + if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1 + != (end - 1) - start) { + abort(); + } + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i], + start1, length); + } + } +} + +int cpu_physical_memory_set_dirty_tracking(int enable) +{ + in_migration = enable; + if (kvm_enabled()) { + return kvm_set_migration_log(enable); + } + return 0; +} + +int cpu_physical_memory_get_dirty_tracking(void) +{ + return in_migration; +} + +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) +{ + int ret = 0; + + if (kvm_enabled()) + ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + return ret; +} + +static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) +{ + ram_addr_t ram_addr; + void *p; + + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK) + + tlb_entry->addend); + ram_addr = qemu_ram_addr_from_host(p); + if (!cpu_physical_memory_is_dirty(ram_addr)) { + tlb_entry->addr_write |= TLB_NOTDIRTY; + } + } +} + +/* update the TLB according to the current state of the dirty bits */ +void cpu_tlb_update_dirty(CPUState *env) +{ + int i; + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_table[mmu_idx][i]); + } +} + +static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) +{ + if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) + tlb_entry->addr_write = vaddr; +} + +/* update the TLB corresponding to virtual page vaddr + so that it is no longer dirty */ +static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr) +{ + int i; + int mmu_idx; + + vaddr &= TARGET_PAGE_MASK; + i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr); +} + +/* add a new TLB entry. At most one entry for a given virtual address + is permitted. Return 0 if OK or 2 if the page could not be mapped + (can only happen in non SOFTMMU mode for I/O pages or pages + conflicting with the host address space). */ +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + PhysPageDesc *p; + unsigned long pd; + unsigned int index; + target_ulong address; + target_ulong code_address; + target_phys_addr_t addend; + int ret; + CPUTLBEntry *te; + CPUWatchpoint *wp; + target_phys_addr_t iotlb; + + p = phys_page_find(paddr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } +#if defined(DEBUG_TLB) + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n", + vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd); +#endif + + ret = 0; + address = vaddr; + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { + /* IO memory case (romd handled later) */ + address |= TLB_MMIO; + } + addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK); + if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { + /* Normal RAM. */ + iotlb = pd & TARGET_PAGE_MASK; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM) + iotlb |= IO_MEM_NOTDIRTY; + else + iotlb |= IO_MEM_ROM; + } else { + /* IO handlers are currently passed a physical address. + It would be nice to pass an offset from the base address + of that region. This would avoid having to special case RAM, + and avoid full address decoding in every device. + We can't use the high bits of pd for this because + IO_MEM_ROMD uses these as a ram address. */ + iotlb = (pd & ~TARGET_PAGE_MASK); + if (p) { + iotlb += p->region_offset; + } else { + iotlb += paddr; + } + } + + code_address = address; + /* Make accesses to pages with watchpoints go via the + watchpoint trap routines. */ + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) { + iotlb = io_mem_watch + paddr; + /* TODO: The memory case can be optimized by not trapping + reads of pages with a write breakpoint. */ + address |= TLB_MMIO; + } + } + + index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + env->iotlb[mmu_idx][index] = iotlb - vaddr; + te = &env->tlb_table[mmu_idx][index]; + te->addend = addend - vaddr; + if (prot & PAGE_READ) { + te->addr_read = address; + } else { + te->addr_read = -1; + } + + if (prot & PAGE_EXEC) { + te->addr_code = code_address; + } else { + te->addr_code = -1; + } + if (prot & PAGE_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* Write access calls the I/O callback. */ + te->addr_write = address | TLB_MMIO; + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + !cpu_physical_memory_is_dirty(pd)) { + te->addr_write = address | TLB_NOTDIRTY; + } else { + te->addr_write = address; + } + } else { + te->addr_write = -1; + } + return ret; +} + +#else + +void tlb_flush(CPUState *env, int flush_global) +{ +} + +void tlb_flush_page(CPUState *env, target_ulong addr) +{ +} + +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int mmu_idx, int is_softmmu) +{ + return 0; +} + +/* + * Walks guest process memory "regions" one by one + * and calls callback function 'fn' for each region. + */ +int walk_memory_regions(void *priv, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)) +{ + unsigned long start, end; + PageDesc *p = NULL; + int i, j, prot, prot1; + int rc = 0; + + start = end = -1; + prot = 0; + + for (i = 0; i <= L1_SIZE; i++) { + p = (i < L1_SIZE) ? l1_map[i] : NULL; + for (j = 0; j < L2_SIZE; j++) { + prot1 = (p == NULL) ? 0 : p[j].flags; + /* + * "region" is one continuous chunk of memory + * that has same protection flags set. + */ + if (prot1 != prot) { + end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); + if (start != -1) { + rc = (*fn)(priv, start, end, prot); + /* callback can stop iteration by returning != 0 */ + if (rc != 0) + return (rc); + } + if (prot1 != 0) + start = end; + else + start = -1; + prot = prot1; + } + if (p == NULL) + break; + } + } + return (rc); +} + +static int dump_region(void *priv, unsigned long start, + unsigned long end, unsigned long prot) +{ + FILE *f = (FILE *)priv; + + (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", + start, end, end - start, + ((prot & PAGE_READ) ? 'r' : '-'), + ((prot & PAGE_WRITE) ? 'w' : '-'), + ((prot & PAGE_EXEC) ? 'x' : '-')); + + return (0); +} + +/* dump memory mappings */ +void page_dump(FILE *f) +{ + (void) fprintf(f, "%-8s %-8s %-8s %s\n", + "start", "end", "size", "prot"); + walk_memory_regions(f, dump_region); +} + +int page_get_flags(target_ulong address) +{ + PageDesc *p; + + p = page_find(address >> TARGET_PAGE_BITS); + if (!p) + return 0; + return p->flags; +} + +/* modify the flags of a page and invalidate the code if + necessary. The flag PAGE_WRITE_ORG is positioned automatically + depending on PAGE_WRITE */ +void page_set_flags(target_ulong start, target_ulong end, int flags) +{ + PageDesc *p; + target_ulong addr; + + /* mmap_lock should already be held. */ + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + if (flags & PAGE_WRITE) + flags |= PAGE_WRITE_ORG; + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* We may be called for host regions that are outside guest + address space. */ + if (!p) + return; + /* if the write protection is set, then we invalidate the code + inside */ + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) && + p->first_tb) { + tb_invalidate_phys_page(addr, 0, NULL); + } + p->flags = flags; + } +} + +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + PageDesc *p; + target_ulong end; + target_ulong addr; + + if (start + len < start) + /* we've wrapped around */ + return -1; + + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ + start = start & TARGET_PAGE_MASK; + + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find(addr >> TARGET_PAGE_BITS); + if( !p ) + return -1; + if( !(p->flags & PAGE_VALID) ) + return -1; + + if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) + return -1; + if (flags & PAGE_WRITE) { + if (!(p->flags & PAGE_WRITE_ORG)) + return -1; + /* unprotect the page if it was put read-only because it + contains translated code */ + if (!(p->flags & PAGE_WRITE)) { + if (!page_unprotect(addr, 0, NULL)) + return -1; + } + return 0; + } + } + return 0; +} + +/* called from signal handler: invalidate the code and unprotect the + page. Return TRUE if the fault was successfully handled. */ +int page_unprotect(target_ulong address, unsigned long pc, void *puc) +{ + unsigned int page_index, prot, pindex; + PageDesc *p, *p1; + target_ulong host_start, host_end, addr; + + /* Technically this isn't safe inside a signal handler. However we + know this only ever happens in a synchronous SEGV handler, so in + practice it seems to be ok. */ + mmap_lock(); + + host_start = address & qemu_host_page_mask; + page_index = host_start >> TARGET_PAGE_BITS; + p1 = page_find(page_index); + if (!p1) { + mmap_unlock(); + return 0; + } + host_end = host_start + qemu_host_page_size; + p = p1; + prot = 0; + for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= p->flags; + p++; + } + /* if the page was really writable, then we change its + protection back to writable */ + if (prot & PAGE_WRITE_ORG) { + pindex = (address - host_start) >> TARGET_PAGE_BITS; + if (!(p1[pindex].flags & PAGE_WRITE)) { + mprotect((void *)g2h(host_start), qemu_host_page_size, + (prot & PAGE_BITS) | PAGE_WRITE); + p1[pindex].flags |= PAGE_WRITE; + /* and since the content will be modified, we must invalidate + the corresponding translated code. */ + tb_invalidate_phys_page(address, pc, puc); +#ifdef DEBUG_TB_CHECK + tb_invalidate_check(address); +#endif + mmap_unlock(); + return 1; + } + } + mmap_unlock(); + return 0; +} + +static inline void tlb_set_dirty(CPUState *env, + unsigned long addr, target_ulong vaddr) +{ +} +#endif /* defined(CONFIG_USER_ONLY) */ + +#if !defined(CONFIG_USER_ONLY) + +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + ram_addr_t memory, ram_addr_t region_offset); +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory, ram_addr_t region_offset); +#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \ + need_subpage) \ + do { \ + if (addr > start_addr) \ + start_addr2 = 0; \ + else { \ + start_addr2 = start_addr & ~TARGET_PAGE_MASK; \ + if (start_addr2 > 0) \ + need_subpage = 1; \ + } \ + \ + if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \ + end_addr2 = TARGET_PAGE_SIZE - 1; \ + else { \ + end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \ + if (end_addr2 < TARGET_PAGE_SIZE - 1) \ + need_subpage = 1; \ + } \ + } while (0) + +/* register physical memory. + For RAM, 'size' must be a multiple of the target page size. + If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an + io memory page. The address used when calling the IO function is + the offset from the start of the region, plus region_offset. Both + start_addr and region_offset are rounded down to a page boundary + before calculating this offset. This should not be a problem unless + the low bits of start_addr and region_offset differ. */ +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset, + ram_addr_t region_offset) +{ + target_phys_addr_t addr, end_addr; + PhysPageDesc *p; + CPUState *env; + ram_addr_t orig_size = size; + void *subpage; + + if (kvm_enabled()) + kvm_set_phys_mem(start_addr, size, phys_offset); + + if (phys_offset == IO_MEM_UNASSIGNED) { + region_offset = start_addr; + } + region_offset &= TARGET_PAGE_MASK; + size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; + end_addr = start_addr + (target_phys_addr_t)size; + for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (p && p->phys_offset != IO_MEM_UNASSIGNED) { + ram_addr_t orig_memory = p->phys_offset; + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, + need_subpage); + if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) { + if (!(orig_memory & IO_MEM_SUBPAGE)) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, orig_memory, + p->region_offset); + } else { + subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK) + >> IO_MEM_SHIFT]; + } + subpage_register(subpage, start_addr2, end_addr2, phys_offset, + region_offset); + p->region_offset = 0; + } else { + p->phys_offset = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) + phys_offset += TARGET_PAGE_SIZE; + } + } else { + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); + p->phys_offset = phys_offset; + p->region_offset = region_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) { + phys_offset += TARGET_PAGE_SIZE; + } else { + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, + end_addr2, need_subpage); + + if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, IO_MEM_UNASSIGNED, + addr & TARGET_PAGE_MASK); + subpage_register(subpage, start_addr2, end_addr2, + phys_offset, region_offset); + p->region_offset = 0; + } + } + } + region_offset += TARGET_PAGE_SIZE; + } + + /* since each CPU stores ram addresses in its TLB cache, we must + reset the modified entries */ + /* XXX: slow ! */ + for(env = first_cpu; env != NULL; env = env->next_cpu) { + tlb_flush(env, 1); + } +} + +/* XXX: temporary until new memory mapping API */ +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) +{ + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return IO_MEM_UNASSIGNED; + return p->phys_offset; +} + +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ + if (kvm_enabled()) + kvm_coalesce_mmio_region(addr, size); +} + +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ + if (kvm_enabled()) + kvm_uncoalesce_mmio_region(addr, size); +} + +#ifdef X49GP +ram_addr_t x49gp_ram_alloc(ram_addr_t size, uint8_t *base); +ram_addr_t x49gp_ram_alloc(ram_addr_t size, uint8_t *base) +{ + RAMBlock *new_block; + + size = TARGET_PAGE_ALIGN(size); + new_block = qemu_malloc(sizeof(*new_block)); + new_block->host = base; + new_block->offset = last_ram_offset; + new_block->length = size; + + new_block->next = ram_blocks; + ram_blocks = new_block; + + last_ram_offset += size; + + return new_block->offset; +} +#else +ram_addr_t qemu_ram_alloc(ram_addr_t size) +{ + RAMBlock *new_block; + + size = TARGET_PAGE_ALIGN(size); + new_block = qemu_malloc(sizeof(*new_block)); + +#if defined(TARGET_S390X) && defined(CONFIG_KVM) + /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */ + new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +#else + new_block->host = qemu_vmalloc(size); +#endif +#ifdef MADV_MERGEABLE + madvise(new_block->host, size, MADV_MERGEABLE); +#endif + new_block->offset = last_ram_offset; + new_block->length = size; + + new_block->next = ram_blocks; + ram_blocks = new_block; + + phys_ram_dirty = qemu_realloc(phys_ram_dirty, + (last_ram_offset + size) >> TARGET_PAGE_BITS); + memset(phys_ram_dirty + (last_ram_offset >> TARGET_PAGE_BITS), + 0xff, size >> TARGET_PAGE_BITS); + + last_ram_offset += size; + + if (kvm_enabled()) + kvm_setup_guest_memory(new_block->host, size); + + return new_block->offset; +} +#endif + +void qemu_ram_free(ram_addr_t addr) +{ + /* TODO: implement this. */ +} + +/* Return a host pointer to ram allocated with qemu_ram_alloc. + With the exception of the softmmu code in this file, this should + only be used for local memory (e.g. video ram) that the device owns, + and knows it isn't going to access beyond the end of the block. + + It should not be used for general purpose DMA. + Use cpu_physical_memory_map/cpu_physical_memory_rw instead. + */ +void *qemu_get_ram_ptr(ram_addr_t addr) +{ + RAMBlock *prev; + RAMBlock **prevp; + RAMBlock *block; + + prev = NULL; + prevp = &ram_blocks; + block = ram_blocks; + while (block && (block->offset > addr + || block->offset + block->length <= addr)) { + if (prev) + prevp = &prev->next; + prev = block; + block = block->next; + } + if (!block) { + fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); + abort(); + } + /* Move this entry to to start of the list. */ + if (prev) { + prev->next = block->next; + block->next = *prevp; + *prevp = block; + } + return block->host + (addr - block->offset); +} + +/* Some of the softmmu routines need to translate from a host pointer + (typically a TLB entry) back to a ram offset. */ +ram_addr_t qemu_ram_addr_from_host(void *ptr) +{ + RAMBlock *prev; + RAMBlock **prevp; + RAMBlock *block; + uint8_t *host = ptr; + + prev = NULL; + prevp = &ram_blocks; + block = ram_blocks; + while (block && (block->host > host + || block->host + block->length <= host)) { + if (prev) + prevp = &prev->next; + prev = block; + block = block->next; + } + if (!block) { + fprintf(stderr, "Bad ram pointer %p\n", ptr); + abort(); + } + return block->offset + (host - block->host); +} + +static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 1); +#endif + return 0; +} + +static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 2); +#endif + return 0; +} + +static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 0, 0, 0, 4); +#endif + return 0; +} + +static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 1); +#endif +} + +static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 2); +#endif +} + +static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); +#endif +#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + do_unassigned_access(addr, 1, 0, 0, 4); +#endif +} + +static CPUReadMemoryFunc * const unassigned_mem_read[3] = { + unassigned_mem_readb, + unassigned_mem_readw, + unassigned_mem_readl, +}; + +static CPUWriteMemoryFunc * const unassigned_mem_write[3] = { + unassigned_mem_writeb, + unassigned_mem_writew, + unassigned_mem_writel, +}; + +static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 1); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stb_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 2); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stw_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, + uint32_t val) +{ + int dirty_flags; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(ram_addr, 4); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; +#endif + } + stl_p(qemu_get_ram_ptr(ram_addr), val); + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); +} + +static CPUReadMemoryFunc * const error_mem_read[3] = { + NULL, /* never used */ + NULL, /* never used */ + NULL, /* never used */ +}; + +static CPUWriteMemoryFunc * const notdirty_mem_write[3] = { + notdirty_mem_writeb, + notdirty_mem_writew, + notdirty_mem_writel, +}; + +/* Generate a debug exception if a watchpoint has been hit. */ +static void check_watchpoint(int offset, int len_mask, int flags) +{ + CPUState *env = cpu_single_env; + target_ulong pc, cs_base; + TranslationBlock *tb; + target_ulong vaddr; + CPUWatchpoint *wp; + int cpu_flags; + + if (env->watchpoint_hit) { + /* We re-entered the check after replacing the TB. Now raise + * the debug interrupt so that is will trigger after the + * current instruction. */ + cpu_interrupt(env, CPU_INTERRUPT_DEBUG); + return; + } + vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + if ((vaddr == (wp->vaddr & len_mask) || + (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) { + wp->flags |= BP_WATCHPOINT_HIT; + if (!env->watchpoint_hit) { + env->watchpoint_hit = wp; + tb = tb_find_pc(env->mem_io_pc); + if (!tb) { + cpu_abort(env, "check_watchpoint: could not find TB for " + "pc=%p", (void *)env->mem_io_pc); + } + cpu_restore_state(tb, env, env->mem_io_pc, NULL); + tb_phys_invalidate(tb, -1); + if (wp->flags & BP_STOP_BEFORE_ACCESS) { + env->exception_index = EXCP_DEBUG; + } else { + cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags); + tb_gen_code(env, pc, cs_base, cpu_flags, 1); + } + cpu_resume_from_signal(env, NULL); + } + } else { + wp->flags &= ~BP_WATCHPOINT_HIT; + } + } +} + +/* Watchpoint access routines. Watchpoints are inserted using TLB tricks, + so these check for a hit then pass through to the normal out-of-line + phys routines. */ +static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ); + return ldub_phys(addr); +} + +static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ); + return lduw_phys(addr); +} + +static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ); + return ldl_phys(addr); +} + +static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE); + stb_phys(addr, val); +} + +static void watch_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE); + stw_phys(addr, val); +} + +static void watch_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE); + stl_phys(addr, val); +} + +static CPUReadMemoryFunc * const watch_mem_read[3] = { + watch_mem_readb, + watch_mem_readw, + watch_mem_readl, +}; + +static CPUWriteMemoryFunc * const watch_mem_write[3] = { + watch_mem_writeb, + watch_mem_writew, + watch_mem_writel, +}; + +static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr, + unsigned int len) +{ + uint32_t ret; + unsigned int idx; + + idx = SUBPAGE_IDX(addr); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__, + mmio, len, addr, idx); +#endif + ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], + addr + mmio->region_offset[idx][0][len]); + + return ret; +} + +static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr, + uint32_t value, unsigned int len) +{ + unsigned int idx; + + idx = SUBPAGE_IDX(addr); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__, + mmio, len, addr, idx, value); +#endif + (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], + addr + mmio->region_offset[idx][1][len], + value); +} + +static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 0); +} + +static void subpage_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 0); +} + +static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 1); +} + +static void subpage_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 1); +} + +static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 2); +} + +static void subpage_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 2); +} + +static CPUReadMemoryFunc * const subpage_read[] = { + &subpage_readb, + &subpage_readw, + &subpage_readl, +}; + +static CPUWriteMemoryFunc * const subpage_write[] = { + &subpage_writeb, + &subpage_writew, + &subpage_writel, +}; + +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + ram_addr_t memory, ram_addr_t region_offset) +{ + int idx, eidx; + unsigned int i; + + if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE) + return -1; + idx = SUBPAGE_IDX(start); + eidx = SUBPAGE_IDX(end); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__, + mmio, start, end, idx, eidx, memory); +#endif + memory >>= IO_MEM_SHIFT; + for (; idx <= eidx; idx++) { + for (i = 0; i < 4; i++) { + if (io_mem_read[memory][i]) { + mmio->mem_read[idx][i] = &io_mem_read[memory][i]; + mmio->opaque[idx][0][i] = io_mem_opaque[memory]; + mmio->region_offset[idx][0][i] = region_offset; + } + if (io_mem_write[memory][i]) { + mmio->mem_write[idx][i] = &io_mem_write[memory][i]; + mmio->opaque[idx][1][i] = io_mem_opaque[memory]; + mmio->region_offset[idx][1][i] = region_offset; + } + } + } + + return 0; +} + +static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, + ram_addr_t orig_memory, ram_addr_t region_offset) +{ + subpage_t *mmio; + int subpage_memory; + + mmio = qemu_mallocz(sizeof(subpage_t)); + + mmio->base = base; + subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, + mmio, base, TARGET_PAGE_SIZE, subpage_memory); +#endif + *phys = subpage_memory | IO_MEM_SUBPAGE; + subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory, + region_offset); + + return mmio; +} + +static int get_free_io_mem_idx(void) +{ + int i; + + for (i = 0; i>= IO_MEM_SHIFT; + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + } + + for(i = 0;i < 3; i++) { + if (!mem_read[i] || !mem_write[i]) + subwidth = IO_MEM_SUBWIDTH; + io_mem_read[io_index][i] = mem_read[i]; + io_mem_write[io_index][i] = mem_write[i]; + } + io_mem_opaque[io_index] = opaque; + return (io_index << IO_MEM_SHIFT) | subwidth; +} + +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque) +{ + return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque); +} + +void cpu_unregister_io_memory(int io_table_address) +{ + int i; + int io_index = io_table_address >> IO_MEM_SHIFT; + + for (i=0;i < 3; i++) { + io_mem_read[io_index][i] = unassigned_mem_read[i]; + io_mem_write[io_index][i] = unassigned_mem_write[i]; + } + io_mem_opaque[io_index] = NULL; + io_mem_used[io_index] = 0; +} + +static void io_mem_init(void) +{ + int i; + + cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL); + for (i=0; i<5; i++) + io_mem_used[i] = 1; + + io_mem_watch = cpu_register_io_memory(watch_mem_read, + watch_mem_write, NULL); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + +/* physical memory access (slow version, mainly for debug) */ +#if defined(CONFIG_USER_ONLY) +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + int l, flags; + target_ulong page; + void * p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = page_get_flags(page); + if (!(flags & PAGE_VALID)) + return; + if (is_write) { + if (!(flags & PAGE_WRITE)) + return; + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_WRITE, addr, l, 0))) + /* FIXME - should this return an error rather than just fail? */ + return; + memcpy(p, buf, l); + unlock_user(p, addr, l); + } else { + if (!(flags & PAGE_READ)) + return; + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_READ, addr, l, 1))) + /* FIXME - should this return an error rather than just fail? */ + return; + memcpy(buf, p, l); + unlock_user(p, addr, 0); + } + len -= l; + buf += l; + addr += l; + } +} + +#else +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + int l, io_index; + uint8_t *ptr; + uint32_t val; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if (is_write) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + target_phys_addr_t addr1 = addr; + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + /* XXX: could force cpu_single_env to NULL to avoid + potential bugs */ + if (l >= 4 && ((addr1 & 3) == 0)) { + /* 32 bit write access */ + val = ldl_p(buf); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val); + l = 4; + } else if (l >= 2 && ((addr1 & 1) == 0)) { + /* 16 bit write access */ + val = lduw_p(buf); + io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val); + l = 2; + } else { + /* 8 bit write access */ + val = ldub_p(buf); + io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val); + l = 1; + } + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = qemu_get_ram_ptr(addr1); + memcpy(ptr, buf, l); + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } + } else { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + target_phys_addr_t addr1 = addr; + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + if (l >= 4 && ((addr1 & 3) == 0)) { + /* 32 bit read access */ + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1); + stl_p(buf, val); + l = 4; + } else if (l >= 2 && ((addr1 & 1) == 0)) { + /* 16 bit read access */ + val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1); + stw_p(buf, val); + l = 2; + } else { + /* 8 bit read access */ + val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1); + stb_p(buf, val); + l = 1; + } + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + memcpy(buf, ptr, l); + } + } + len -= l; + buf += l; + addr += l; + } +} + +/* used for ROM loading : can write in RAM and ROM */ +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + int l; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* do nothing */ + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* ROM/RAM case */ + ptr = qemu_get_ram_ptr(addr1); + memcpy(ptr, buf, l); + } + len -= l; + buf += l; + addr += l; + } +} + +typedef struct { + void *buffer; + target_phys_addr_t addr; + target_phys_addr_t len; +} BounceBuffer; + +static BounceBuffer bounce; + +typedef struct MapClient { + void *opaque; + void (*callback)(void *opaque); + QLIST_ENTRY(MapClient) link; +} MapClient; + +static QLIST_HEAD(map_client_list, MapClient) map_client_list + = QLIST_HEAD_INITIALIZER(map_client_list); + +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)) +{ + MapClient *client = qemu_malloc(sizeof(*client)); + + client->opaque = opaque; + client->callback = callback; + QLIST_INSERT_HEAD(&map_client_list, client, link); + return client; +} + +void cpu_unregister_map_client(void *_client) +{ + MapClient *client = (MapClient *)_client; + + QLIST_REMOVE(client, link); + qemu_free(client); +} + +static void cpu_notify_map_clients(void) +{ + MapClient *client; + + while (!QLIST_EMPTY(&map_client_list)) { + client = QLIST_FIRST(&map_client_list); + client->callback(client->opaque); + cpu_unregister_map_client(client); + } +} + +/* Map a physical memory region into a host virtual address. + * May map a subset of the requested range, given by and returned in *plen. + * May return NULL if resources needed to perform the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. + */ +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write) +{ + target_phys_addr_t len = *plen; + target_phys_addr_t done = 0; + int l; + uint8_t *ret = NULL; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + unsigned long addr1; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + if (done || bounce.buffer) { + break; + } + bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); + bounce.addr = addr; + bounce.len = l; + if (!is_write) { + cpu_physical_memory_rw(addr, bounce.buffer, l, 0); + } + ptr = bounce.buffer; + } else { + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + ptr = qemu_get_ram_ptr(addr1); + } + if (!done) { + ret = ptr; + } else if (ret + done != ptr) { + break; + } + + len -= l; + addr += l; + done += l; + } + *plen = done; + return ret; +} + +/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). + * Will also mark the memory as dirty if is_write == 1. access_len gives + * the amount of memory that was actually read or written by the caller. + */ +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) +{ + if (buffer != bounce.buffer) { + if (is_write) { + ram_addr_t addr1 = qemu_ram_addr_from_host(buffer); + while (access_len) { + unsigned l; + l = TARGET_PAGE_SIZE; + if (l > access_len) + l = access_len; + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + addr1 += l; + access_len -= l; + } + } + return; + } + if (is_write) { + cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len); + } + qemu_free(bounce.buffer); + bounce.buffer = NULL; + cpu_notify_map_clients(); +} + +/* warning: addr must be aligned */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint32_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldl_p(ptr); + } + return val; +} + +/* warning: addr must be aligned */ +uint64_t ldq_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint64_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#ifdef TARGET_WORDS_BIGENDIAN + val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32; + val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4); +#else + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32; +#endif + } else { + /* RAM case */ + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldq_p(ptr); + } + return val; +} + +/* XXX: optimize */ +uint32_t ldub_phys(target_phys_addr_t addr) +{ + uint8_t val; + cpu_physical_memory_read(addr, &val, 1); + return val; +} + +/* XXX: optimize */ +uint32_t lduw_phys(target_phys_addr_t addr) +{ + uint16_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 2); + return tswap16(val); +} + +/* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + ptr = qemu_get_ram_ptr(addr1); + stl_p(ptr, val); + + if (unlikely(in_migration)) { + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } + } +} + +void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val); +#else + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32); +#endif + } else { + ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + stq_p(ptr, val); + } +} + +/* warning: addr must be aligned */ +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (p) + addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = qemu_get_ram_ptr(addr1); + stl_p(ptr, val); + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } +} + +/* XXX: optimize */ +void stb_phys(target_phys_addr_t addr, uint32_t val) +{ + uint8_t v = val; + cpu_physical_memory_write(addr, &v, 1); +} + +/* XXX: optimize */ +void stw_phys(target_phys_addr_t addr, uint32_t val) +{ + uint16_t v = tswap16(val); + cpu_physical_memory_write(addr, (const uint8_t *)&v, 2); +} + +/* XXX: optimize */ +void stq_phys(target_phys_addr_t addr, uint64_t val) +{ + val = tswap64(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); +} + +#endif + +/* virtual memory access for debug (includes writing to ROM) */ +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int l; + target_phys_addr_t phys_addr; + target_ulong page; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + phys_addr = cpu_get_phys_page_debug(env, page); + /* if no physical page mapped, return an error */ + if (phys_addr == -1) + return -1; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + phys_addr += (addr & ~TARGET_PAGE_MASK); +#if !defined(CONFIG_USER_ONLY) + if (is_write) + cpu_physical_memory_write_rom(phys_addr, buf, l); + else +#endif + cpu_physical_memory_rw(phys_addr, buf, l, is_write); + len -= l; + buf += l; + addr += l; + } + return 0; +} + +/* in deterministic execution mode, instructions doing device I/Os + must be at the end of the TB */ +void cpu_io_recompile(CPUState *env, void *retaddr) +{ + TranslationBlock *tb; + uint32_t n, cflags; + target_ulong pc, cs_base; + uint64_t flags; + + tb = tb_find_pc((unsigned long)retaddr); + if (!tb) { + cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", + retaddr); + } + n = env->icount_decr.u16.low + tb->icount; + cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); + /* Calculate how many instructions had been executed before the fault + occurred. */ + n = n - env->icount_decr.u16.low; + /* Generate a new TB ending on the I/O insn. */ + n++; + /* On MIPS and SH, delay slot instructions can only be restarted if + they were already the first instruction in the TB. If this is not + the first instruction in a TB then re-execute the preceding + branch. */ +#if defined(TARGET_MIPS) + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { + env->active_tc.PC -= 4; + env->icount_decr.u16.low++; + env->hflags &= ~MIPS_HFLAG_BMASK; + } +#elif defined(TARGET_SH4) + if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 + && n > 1) { + env->pc -= 2; + env->icount_decr.u16.low++; + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + } +#endif + /* This should never happen. */ + if (n > CF_COUNT_MASK) + cpu_abort(env, "TB too big during recompile"); + + cflags = n | CF_LAST_IO; + pc = tb->pc; + cs_base = tb->cs_base; + flags = tb->flags; + tb_phys_invalidate(tb, -1); + /* FIXME: In theory this could raise an exception. In practice + we have already translated the block once so it's probably ok. */ + tb_gen_code(env, pc, cs_base, flags, cflags); + /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not + the first in the TB) then we end up generating a whole new TB and + repeating the fault, which is horribly inefficient. + Better would be to execute just this insn uncached, or generate a + second new TB. */ + cpu_resume_from_signal(env, NULL); +} + +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i, target_code_size, max_target_code_size; + int direct_jmp_count, direct_jmp2_count, cross_page; + TranslationBlock *tb; + + target_code_size = 0; + max_target_code_size = 0; + cross_page = 0; + direct_jmp_count = 0; + direct_jmp2_count = 0; + for(i = 0; i < nb_tbs; i++) { + tb = &tbs[i]; + target_code_size += tb->size; + if (tb->size > max_target_code_size) + max_target_code_size = tb->size; + if (tb->page_addr[1] != -1) + cross_page++; + if (tb->tb_next_offset[0] != 0xffff) { + direct_jmp_count++; + if (tb->tb_next_offset[1] != 0xffff) { + direct_jmp2_count++; + } + } + } + /* XXX: avoid using doubles ? */ + cpu_fprintf(f, "Translation buffer state:\n"); + cpu_fprintf(f, "gen code size %ld/%ld\n", + code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); + cpu_fprintf(f, "TB count %d/%d\n", + nb_tbs, code_gen_max_blocks); + cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", + nb_tbs ? target_code_size / nb_tbs : 0, + max_target_code_size); + cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, + target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", + cross_page, + nb_tbs ? (cross_page * 100) / nb_tbs : 0); + cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", + direct_jmp_count, + nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, + direct_jmp2_count, + nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + cpu_fprintf(f, "\nStatistics:\n"); + cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); + cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); + cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); + tcg_dump_info(f, cpu_fprintf); +} + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _cmmu +#define GETPC() NULL +#define env cpu_single_env +#define SOFTMMU_CODE_ACCESS + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +#undef env + +#endif diff --git a/qemu/qemu-git/feature_to_c.sh b/qemu/qemu-git/feature_to_c.sh new file mode 100644 index 0000000..dbf9f19 --- /dev/null +++ b/qemu/qemu-git/feature_to_c.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +# Convert text files to compilable C arrays. +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +output=$1 +shift + +if test -z "$output" || test -z "$1"; then + echo "Usage: $0 OUTPUTFILE INPUTFILE..." + exit 1 +fi + +if test -e "$output"; then + echo "Output file \"$output\" already exists; refusing to overwrite." + exit 1 +fi + +for input; do + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + + ${AWK:-awk} 'BEGIN { n = 0 + print "static const char '$arrayname'[] = {" + for (i = 0; i < 255; i++) + _ord_[sprintf("%c", i)] = i + } { + split($0, line, ""); + printf " " + for (i = 1; i <= length($0); i++) { + c = line[i] + if (c == "'\''") { + printf "'\''\\'\'''\'', " + } else if (c == "\\") { + printf "'\''\\\\'\'', " + } else if (_ord_[c] >= 32 && _ord_[c] < 127) { + printf "'\''%s'\'', ", c + } else { + printf "'\''\\%03o'\'', ", _ord_[c] + } + if (i % 10 == 0) + printf "\n " + } + printf "'\''\\n'\'', \n" + } END { + print " 0 };" + }' < $input >> $output +done + +echo >> $output +echo "extern const char *const xml_builtin[][2];" >> $output +echo "const char *const xml_builtin[][2] = {" >> $output + +for input; do + basename=`echo $input | sed 's,.*/,,'` + arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` + echo " { \"$basename\", $arrayname }," >> $output +done + +echo " { (char *)0, (char *)0 }" >> $output +echo "};" >> $output diff --git a/qemu/qemu-git/fpu/.svn/all-wcprops b/qemu/qemu-git/fpu/.svn/all-wcprops new file mode 100644 index 0000000..2e7c8ea --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/all-wcprops @@ -0,0 +1,41 @@ +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu +END +softfloat.c +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat.c +END +softfloat-native.c +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat-native.c +END +softfloat.h +K 25 +svn:wc:ra_dav:version-url +V 55 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat.h +END +softfloat-macros.h +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat-macros.h +END +softfloat-native.h +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat-native.h +END +softfloat-specialize.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/fpu/softfloat-specialize.h +END diff --git a/qemu/qemu-git/fpu/.svn/entries b/qemu/qemu-git/fpu/.svn/entries new file mode 100644 index 0000000..64be2aa --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/entries @@ -0,0 +1,232 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/fpu +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +softfloat.c +file + + + + +2013-08-23T00:54:47.000000Z +0b3793748829fed59c7aa55adc700053 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +207050 + +softfloat-native.c +file + + + + +2013-08-23T00:54:47.000000Z +f152968e52fd15de1bf1ef195c68ff39 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +11811 + +softfloat.h +file + + + + +2013-08-23T00:54:47.000000Z +39d28f3f5843fac5d8139e10a33fe071 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +19371 + +softfloat-macros.h +file + + + + +2013-08-23T00:54:47.000000Z +87d6d6aad7c99d9ac658c7fbda47f173 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +24415 + +softfloat-native.h +file + + + + +2013-08-23T00:54:47.000000Z +41097777be4808d6fd80eba702910a04 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +13669 + +softfloat-specialize.h +file + + + + +2013-08-23T00:54:47.000000Z +2535e36d91238348376b41ba6fea35b0 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +20704 + diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat-macros.h.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat-macros.h.svn-base new file mode 100644 index 0000000..7838228 --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat-macros.h.svn-base @@ -0,0 +1,719 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 32, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 64, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +| _plus_ the number of bits given in `count'. The shifted result is at most +| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +| bits shifted off form a second 64-bit result as follows: The _last_ bit +| shifted off is the most-significant bit of the extra result, and the other +| 63 bits of the extra result are all zero if and only if _all_but_the_last_ +| bits shifted off were all zero. This extra result is stored in the location +| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. +| (This routine makes more sense if `a0' and `a1' are considered to form +| a fixed-point value with binary point between `a0' and `a1'. This fixed- +| point value is shifted right by the number of bits given in `count', and +| the integer part of the result is returned at the location pointed to by +| `z0Ptr'. The fractional part of the result may be slightly corrupted as +| described above, and is returned at the location pointed to by `z1Ptr'.) +*----------------------------------------------------------------------------*/ + +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' can be arbitrarily large; in particular, if `count' is greater +| than 128, the result will be 0. The result is broken into two 64-bit pieces +| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. If any nonzero bits are shifted off, they +| are ``jammed'' into the least significant bit of the result by setting the +| least significant bit to 1. The value of `count' can be arbitrarily large; +| in particular, if `count' is greater than 128, the result will be either +| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or +| nonzero. The result is broken into two 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 64. The result is broken into two 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/*---------------------------------------------------------------------------- +| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +| by the number of bits given in `count'. Any bits shifted off are lost. +| The value of `count' must be less than 64. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +| any carry out is lost. The result is broken into two 64-bit pieces which +| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/*---------------------------------------------------------------------------- +| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +| modulo 2^192, so any carry out is lost. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +| 2^128, so any borrow out (carry out) is lost. The result is broken into two +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +| `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +| from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +| result is broken into three 64-bit pieces which are stored at the locations +| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +| into two 64-bit pieces which are stored at the locations pointed to by +| `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by +| `b' to obtain a 192-bit product. The product is broken into three 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +| `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +| product. The product is broken into four 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the 64-bit integer quotient obtained by dividing +| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The +| divisor `b' must be at least 2^63. If q is the exact quotient truncated +| toward zero, the approximation returned lies between q and q + 2 inclusive. +| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +| unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the square root of the 32-bit significand given +| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +| `aExp' (the least significant bit) is 1, the integer returned approximates +| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +| case, the approximation returned lies strictly within +/-2 of the exact +| value. +*----------------------------------------------------------------------------*/ + +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 32 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 64 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +| is equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +| not equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.c.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.c.svn-base new file mode 100644 index 0000000..8d64f4e --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.c.svn-base @@ -0,0 +1,534 @@ +/* Native implementation of soft float functions. Only a single status + context is supported */ +#include "softfloat.h" +#include +#if defined(CONFIG_SOLARIS) +#include +#endif + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) || \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) + fpsetround(val); +#elif defined(__arm__) + /* nothing to do */ +#else + fesetround(val); +#endif +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +#if defined(CONFIG_BSD) || \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#define lrintf(f) ((int32_t)rint(f)) +#define llrintf(f) ((int64_t)rint(f)) +#define sqrtf(f) ((float)sqrt(f)) +#define remainderf(fa, fb) ((float)remainder(fa, fb)) +#define rintf(f) ((float)rint(f)) +#if !defined(__sparc__) && \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +extern long double rintl(long double); +extern long double scalbnl(long double, int); + +long long +llrintl(long double x) { + return ((long long) rintl(x)); +} + +long +lrintl(long double x) { + return ((long) rintl(x)); +} + +long double +ldexpl(long double x, int n) { + return (scalbnl(x, n)); +} +#endif +#endif + +#if defined(_ARCH_PPC) + +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +static double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} + +#define rint qemu_rint +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32(int v STATUS_PARAM) +{ + return (float32)v; +} + +float32 uint32_to_float32(unsigned int v STATUS_PARAM) +{ + return (float32)v; +} + +float64 int32_to_float64(int v STATUS_PARAM) +{ + return (float64)v; +} + +float64 uint32_to_float64(unsigned int v STATUS_PARAM) +{ + return (float64)v; +} + +#ifdef FLOATX80 +floatx80 int32_to_floatx80(int v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif +float32 int64_to_float32( int64_t v STATUS_PARAM) +{ + return (float32)v; +} +float32 uint64_to_float32( uint64_t v STATUS_PARAM) +{ + return (float32)v; +} +float64 int64_to_float64( int64_t v STATUS_PARAM) +{ + return (float64)v; +} +float64 uint64_to_float64( uint64_t v STATUS_PARAM) +{ + return (float64)v; +} +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif + +/* XXX: this code implements the x86 behaviour, not the IEEE one. */ +#if HOST_LONG_BITS == 32 +static inline int long_to_int32(long a) +{ + return a; +} +#else +static inline int long_to_int32(long a) +{ + if (a != (int32_t)a) + a = 0x80000000; + return a; +} +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 a STATUS_PARAM) +{ + return long_to_int32(lrintf(a)); +} +int float32_to_int32_round_to_zero( float32 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float32_to_int64( float32 a STATUS_PARAM) +{ + return llrintf(a); +} + +int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM) +{ + return (int64_t)a; +} + +float64 float32_to_float64( float32 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 a STATUS_PARAM) +{ + return a; +} +#endif + +unsigned int float32_to_uint32( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrintf(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + return rintf(a); +} + +float32 float32_rem( float32 a, float32 b STATUS_PARAM) +{ + return remainderf(a, b); +} + +float32 float32_sqrt( float32 a STATUS_PARAM) +{ + return sqrtf(a); +} +int float32_compare( float32 a, float32 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float32_is_signaling_nan( float32 a1) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +} + +int float32_is_nan( float32 a1 ) +{ + float32u u; + uint64_t a; + u.f = a1; + a = u.i; + return ( 0xFF800000 < ( a<<1 ) ); +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 a STATUS_PARAM) +{ + return long_to_int32(lrint(a)); +} +int float64_to_int32_round_to_zero( float64 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float64_to_int64( float64 a STATUS_PARAM) +{ + return llrint(a); +} +int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 float64_to_float32( float64 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 a STATUS_PARAM) +{ + return a; +} +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 a STATUS_PARAM) +{ + return a; +} +#endif + +unsigned int float64_to_uint32( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrint(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = llrint(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = (int64_t)(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +#if defined(__sun__) && \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +static inline float64 trunc(float64 x) +{ + return x < 0 ? -floor(-x) : floor(x); +} +#endif +float64 float64_trunc_to_int( float64 a STATUS_PARAM ) +{ + return trunc(a); +} + +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ +#if defined(__arm__) + switch(STATUS(float_rounding_mode)) { + default: + case float_round_nearest_even: + asm("rndd %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_down: + asm("rnddm %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_up: + asm("rnddp %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_to_zero: + asm("rnddz %0, %1" : "=f" (a) : "f"(a)); + break; + } +#else + return rint(a); +#endif +} + +float64 float64_rem( float64 a, float64 b STATUS_PARAM) +{ + return remainder(a, b); +} + +float64 float64_sqrt( float64 a STATUS_PARAM) +{ + return sqrt(a); +} +int float64_compare( float64 a, float64 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float64_is_signaling_nan( float64 a1) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +int float64_is_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 a STATUS_PARAM) +{ + return long_to_int32(lrintl(a)); +} +int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int)a; +} +int64_t floatx80_to_int64( floatx80 a STATUS_PARAM) +{ + return llrintl(a); +} +int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 floatx80_to_float32( floatx80 a STATUS_PARAM) +{ + return a; +} +float64 floatx80_to_float64( floatx80 a STATUS_PARAM) +{ + return a; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM) +{ + return rintl(a); +} +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM) +{ + return remainderl(a, b); +} +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) +{ + return sqrtl(a); +} +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int floatx80_is_signaling_nan( floatx80 a1) +{ + floatx80u u; + uint64_t aLow; + u.f = a1; + + aLow = u.i.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( u.i.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( u.i.low == aLow ); +} + +int floatx80_is_nan( floatx80 a1 ) +{ + floatx80u u; + u.f = a1; + return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 ); +} + +#endif diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.h.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.h.svn-base new file mode 100644 index 0000000..fe737b3 --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat-native.h.svn-base @@ -0,0 +1,499 @@ +/* Native implementation of soft float functions */ +#include + +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \ + || defined(CONFIG_SOLARIS) +#include +#define fabsf(f) ((float)fabs(f)) +#else +#include +#endif + +#if defined(__OpenBSD__) || defined(__NetBSD__) +#include +#endif + +/* + * Define some C99-7.12.3 classification macros and + * some C99-.12.4 for Solaris systems OS less than 10, + * or Solaris 10 systems running GCC 3.x or less. + * Solaris 10 with GCC4 does not need these macros as they + * are defined in with a compiler directive + */ +#if defined(CONFIG_SOLARIS) && \ + ((CONFIG_SOLARIS_VERSION <= 9 ) || \ + ((CONFIG_SOLARIS_VERSION == 10) && (__GNUC__ < 4))) \ + || (defined(__OpenBSD__) && (OpenBSD < 200811)) +/* + * C99 7.12.3 classification macros + * and + * C99 7.12.14 comparison macros + * + * ... do not work on Solaris 10 using GNU CC 3.4.x. + * Try to workaround the missing / broken C99 math macros. + */ +#if defined(__OpenBSD__) +#define unordered(x, y) (isnan(x) || isnan(y)) +#endif + +#ifdef __NetBSD__ +#ifndef isgreater +#define isgreater(x, y) __builtin_isgreater(x, y) +#endif +#ifndef isgreaterequal +#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y) +#endif +#ifndef isless +#define isless(x, y) __builtin_isless(x, y) +#endif +#ifndef islessequal +#define islessequal(x, y) __builtin_islessequal(x, y) +#endif +#ifndef isunordered +#define isunordered(x, y) __builtin_isunordered(x, y) +#endif +#endif + + +#define isnormal(x) (fpclass(x) >= FP_NZERO) +#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) +#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y))) +#define isless(x, y) ((!unordered(x, y)) && ((x) < (y))) +#define islessequal(x, y) ((!unordered(x, y)) && ((x) <= (y))) +#define isunordered(x,y) unordered(x, y) +#endif + +#if defined(__sun__) && !defined(CONFIG_NEEDS_LIBSUNMATH) + +#ifndef isnan +# define isnan(x) \ + (sizeof (x) == sizeof (long double) ? isnan_ld (x) \ + : sizeof (x) == sizeof (double) ? isnan_d (x) \ + : isnan_f (x)) +static inline int isnan_f (float x) { return x != x; } +static inline int isnan_d (double x) { return x != x; } +static inline int isnan_ld (long double x) { return x != x; } +#endif + +#ifndef isinf +# define isinf(x) \ + (sizeof (x) == sizeof (long double) ? isinf_ld (x) \ + : sizeof (x) == sizeof (double) ? isinf_d (x) \ + : isinf_f (x)) +static inline int isinf_f (float x) { return isnan (x - x); } +static inline int isinf_d (double x) { return isnan (x - x); } +static inline int isinf_ld (long double x) { return isnan (x - x); } +#endif +#endif + +typedef float float32; +typedef double float64; +#ifdef FLOATX80 +typedef long double floatx80; +#endif + +typedef union { + float32 f; + uint32_t i; +} float32u; +typedef union { + float64 f; + uint64_t i; +} float64u; +#ifdef FLOATX80 +typedef union { + floatx80 f; + struct { + uint64_t low; + uint16_t high; + } i; +} floatx80u; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \ + || defined(CONFIG_SOLARIS) +#if defined(__OpenBSD__) +#define FE_RM FP_RM +#define FE_RP FP_RP +#define FE_RZ FP_RZ +#endif +enum { + float_round_nearest_even = FP_RN, + float_round_down = FP_RM, + float_round_up = FP_RP, + float_round_to_zero = FP_RZ +}; +#elif defined(__arm__) +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; +#else +enum { + float_round_nearest_even = FE_TONEAREST, + float_round_down = FE_DOWNWARD, + float_round_up = FE_UPWARD, + float_round_to_zero = FE_TOWARDZERO +}; +#endif + +typedef struct float_status { + int float_rounding_mode; +#ifdef FLOATX80 + int floatx80_rounding_precision; +#endif +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM); +float32 uint32_to_float32( unsigned int STATUS_PARAM); +float64 int32_to_float64( int STATUS_PARAM); +float64 uint32_to_float64( unsigned int STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM); +float32 uint64_to_float32( uint64_t STATUS_PARAM); +float64 int64_to_float64( int64_t STATUS_PARAM); +float64 uint64_to_float64( uint64_t v STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM); +unsigned int float32_to_uint32( float32 a STATUS_PARAM); +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM); +int64_t float32_to_int64( float32 STATUS_PARAM); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM); +float64 float32_to_float64( float32 STATUS_PARAM); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM); +INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM) +{ + return a + b; +} +INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM) +{ + return a - b; +} +INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM) +{ + return a * b; +} +INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) +{ + return a / b; +} +float32 float32_rem( float32, float32 STATUS_PARAM); +float32 float32_sqrt( float32 STATUS_PARAM); +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) +{ + return a == b; +} +INLINE int float32_le( float32 a, float32 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) +{ + return a < b; +} +INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isless(a, b); +} +INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_signaling_nan( float32 ); +int float32_is_nan( float32 ); + +INLINE float32 float32_abs(float32 a) +{ + return fabsf(a); +} + +INLINE float32 float32_chs(float32 a) +{ + return -a; +} + +INLINE float32 float32_is_infinity(float32 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float32 float32_is_neg(float32 a) +{ + float32u u; + u.f = a; + return u.i >> 31; +} + +INLINE float32 float32_is_zero(float32 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE float32 float32_scalbn(float32 a, int n) +{ + return scalbnf(a, n); +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64( float64 STATUS_PARAM ); +uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM ); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); +INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM) +{ + return a + b; +} +INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM) +{ + return a - b; +} +INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM) +{ + return a * b; +} +INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) +{ + return a / b; +} +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) +{ + return a == b; +} +INLINE int float64_le( float64 a, float64 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) +{ + return a < b; +} +INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isless(a, b); + +} +INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_signaling_nan( float64 ); +int float64_is_nan( float64 ); + +INLINE float64 float64_abs(float64 a) +{ + return fabs(a); +} + +INLINE float64 float64_chs(float64 a) +{ + return -a; +} + +INLINE float64 float64_is_infinity(float64 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float64 float64_is_neg(float64 a) +{ + float64u u; + u.f = a; + return u.i >> 63; +} + +INLINE float64 float64_is_zero(float64 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE float64 float64_scalbn(float64 a, int n) +{ + return scalbn(a, n); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a + b; +} +INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a - b; +} +INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a * b; +} +INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a / b; +} +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a == b; +} +INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a < b; +} +INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isless(a, b); + +} +INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_signaling_nan( floatx80 ); +int floatx80_is_nan( floatx80 ); + +INLINE floatx80 floatx80_abs(floatx80 a) +{ + return fabsl(a); +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + return -a; +} + +INLINE floatx80 floatx80_is_infinity(floatx80 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE floatx80 floatx80_is_neg(floatx80 a) +{ + floatx80u u; + u.f = a; + return u.i.high >> 15; +} + +INLINE floatx80 floatx80_is_zero(floatx80 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +{ + return scalbnl(a, n); +} + +#endif diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat-specialize.h.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat-specialize.h.svn-base new file mode 100644 index 0000000..8e6aceb --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat-specialize.h.svn-base @@ -0,0 +1,581 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define SNAN_BIT_IS_ONE 1 +#else +#define SNAN_BIT_IS_ONE 0 +#endif + +/*---------------------------------------------------------------------------- +| Raises the exceptions specified by `flags'. Floating-point traps can be +| defined here if desired. It is currently not possible for such a trap +| to substitute a result value. If traps are not implemented, this routine +| should be simply `float_exception_flags |= flags;'. +*----------------------------------------------------------------------------*/ + +void float_raise( int8 flags STATUS_PARAM ) +{ + STATUS(float_exception_flags) |= flags; +} + +/*---------------------------------------------------------------------------- +| Internal canonical NaN format. +*----------------------------------------------------------------------------*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float32_default_nan make_float32(0x7FFFFFFF) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float32_default_nan make_float32(0x7FC00000) +#elif defined(TARGET_HPPA) +#define float32_default_nan make_float32(0x7FA00000) +#elif SNAN_BIT_IS_ONE +#define float32_default_nan make_float32(0x7FBFFFFF) +#else +#define float32_default_nan make_float32(0xFFC00000) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float32_is_nan( float32 a_ ) +{ + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#else + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float32_is_signaling_nan( float32 a_ ) +{ + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#else + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); + z.sign = float32_val(a)>>31; + z.low = 0; + z.high = ( (bits64) float32_val(a) )<<41; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the single- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float32 commonNaNToFloat32( commonNaNT a ) +{ + bits32 mantissa = a.high>>41; + if ( mantissa ) + return make_float32( + ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); + else + return float32_default_nan; +} + +/*---------------------------------------------------------------------------- +| Takes two single-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits32 av, bv, res; + + if ( STATUS(default_nan_mode) ) + return float32_default_nan; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + av = float32_val(a); + bv = float32_val(b); +#if SNAN_BIT_IS_ONE + av &= ~0x00400000; + bv &= ~0x00400000; +#else + av |= 0x00400000; + bv |= 0x00400000; +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + res = bIsNaN ? bv : av; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) + res = av; + else { + returnLargerSignificand: + if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) + res = bv; + else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } + } + else { + res = bv; + } + return make_float32(res); +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) +#elif defined(TARGET_HPPA) +#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) +#elif SNAN_BIT_IS_ONE +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) +#else +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float64_is_nan( float64 a_ ) +{ + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#else + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float64_is_signaling_nan( float64 a_ ) +{ + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#else + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = float64_val(a)>>63; + z.low = 0; + z.high = float64_val(a)<<12; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the double- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float64 commonNaNToFloat64( commonNaNT a ) +{ + bits64 mantissa = a.high>>12; + + if ( mantissa ) + return make_float64( + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF0000000000000 ) + | ( a.high>>12 )); + else + return float64_default_nan; +} + +/*---------------------------------------------------------------------------- +| Takes two double-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits64 av, bv, res; + + if ( STATUS(default_nan_mode) ) + return float64_default_nan; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + av = float64_val(a); + bv = float64_val(b); +#if SNAN_BIT_IS_ONE + av &= ~LIT64( 0x0008000000000000 ); + bv &= ~LIT64( 0x0008000000000000 ); +#else + av |= LIT64( 0x0008000000000000 ); + bv |= LIT64( 0x0008000000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + res = bIsNaN ? bv : av; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) + res = av; + else { + returnLargerSignificand: + if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) + res = bv; + else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } + } + else { + res = bv; + } + return make_float64(res); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. The +| `high' and `low' values hold the most- and least-significant bits, +| respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define floatx80_default_nan_high 0x7FFF +#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) +#else +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xC000000000000000 ) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| quiet NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int floatx80_is_nan( floatx80 a ) +{ +#if SNAN_BIT_IS_ONE + bits64 aLow; + + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#else + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int floatx80_is_signaling_nan( floatx80 a ) +{ +#if SNAN_BIT_IS_ONE + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#else + bits64 aLow; + + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +| invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the extended +| double-precision floating-point format. +*----------------------------------------------------------------------------*/ + +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + if (a.high) + z.low = a.high; + else + z.low = floatx80_default_nan_low; + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; +} + +/*---------------------------------------------------------------------------- +| Takes two extended double-precision floating-point values `a' and `b', one +| of which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + if ( STATUS(default_nan_mode) ) { + a.low = floatx80_default_nan_low; + a.high = floatx80_default_nan_high; + return a; + } + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.low &= ~LIT64( 0xC000000000000000 ); + b.low &= ~LIT64( 0xC000000000000000 ); +#else + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) return a; + returnLargerSignificand: + if ( a.low < b.low ) return b; + if ( b.low < a.low ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated quadruple-precision NaN. The `high' and +| `low' values hold the most- and least-significant bits, respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) +#else +#define float128_default_nan_high LIT64( 0xFFFF800000000000 ) +#define float128_default_nan_low LIT64( 0x0000000000000000 ) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float128_is_nan( float128 a ) +{ +#if SNAN_BIT_IS_ONE + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#else + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float128_is_signaling_nan( float128 a ) +{ +#if SNAN_BIT_IS_ONE + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#else + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>63; + shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the quadruple- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float128 commonNaNToFloat128( commonNaNT a ) +{ + float128 z; + + shift128Right( a.high, a.low, 16, &z.high, &z.low ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); + return z; +} + +/*---------------------------------------------------------------------------- +| Takes two quadruple-precision floating-point values `a' and `b', one of +| which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + if ( STATUS(default_nan_mode) ) { + a.low = float128_default_nan_low; + a.high = float128_default_nan_high; + return a; + } + + aIsNaN = float128_is_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsNaN = float128_is_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.high &= ~LIT64( 0x0000800000000000 ); + b.high &= ~LIT64( 0x0000800000000000 ); +#else + a.high |= LIT64( 0x0000800000000000 ); + b.high |= LIT64( 0x0000800000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) return a; + returnLargerSignificand: + if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b; + if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } +} + +#endif diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat.c.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat.c.svn-base new file mode 100644 index 0000000..395f9b1 --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat.c.svn-base @@ -0,0 +1,5808 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also + be flushed to zero. */ +#include "softfloat.h" + +/*---------------------------------------------------------------------------- +| Primitive arithmetic functions, including multi-word arithmetic, and +| division and square root approximations. (Can be specialized to target if +| desired.) +*----------------------------------------------------------------------------*/ +#include "softfloat-macros.h" + +/*---------------------------------------------------------------------------- +| Functions and definitions to determine: (1) whether tininess for underflow +| is detected before or after rounding by default, (2) what (if anything) +| happens when exceptions are raised, (3) how signaling NaNs are distinguished +| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +| are propagated from function inputs to output. These details are target- +| specific. +*----------------------------------------------------------------------------*/ +#include "softfloat-specialize.h" + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +} + +void set_float_exception_flags(int val STATUS_PARAM) +{ + STATUS(float_exception_flags) = val; +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +/*---------------------------------------------------------------------------- +| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +| and 7, and returns the properly rounded 32-bit integer corresponding to the +| input. If `zSign' is 1, the input is negated before being converted to an +| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input +| is simply rounded to an integer, with the inexact exception raised if the +| input cannot be represented exactly as an integer. However, if the fixed- +| point input is too large, the invalid exception is raised and the largest +| positive or negative integer is returned. +*----------------------------------------------------------------------------*/ + +static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_raise( float_flag_invalid STATUS_VAR); + return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and +| `absZ1', with binary point between bits 63 and 64 (between the input words), +| and returns the properly rounded 64-bit integer corresponding to the input. +| If `zSign' is 1, the input is negated before being converted to an integer. +| Ordinarily, the fixed-point input is simply rounded to an integer, with +| the inexact exception raised if the input cannot be represented exactly as +| an integer. However, if the fixed-point input is too large, the invalid +| exception is raised and the largest positive or negative integer is +| returned. +*----------------------------------------------------------------------------*/ + +static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven, increment; + int64 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + increment = ( (sbits64) absZ1 < 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + increment = 0; + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && absZ1; + } + else { + increment = ( roundingMode == float_round_up ) && absZ1; + } + } + } + if ( increment ) { + ++absZ0; + if ( absZ0 == 0 ) goto overflow; + absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + } + z = absZ0; + if ( zSign ) z = - z; + if ( z && ( ( z < 0 ) ^ zSign ) ) { + overflow: + float_raise( float_flag_invalid STATUS_VAR); + return + zSign ? (sbits64) LIT64( 0x8000000000000000 ) + : LIT64( 0x7FFFFFFFFFFFFFFF ); + } + if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the fraction bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return float32_val(a) & 0x007FFFFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( float32_val(a)>>23 ) & 0xFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat32Sign( float32 a ) +{ + + return float32_val(a)>>31; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal single-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper single-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat32' except that `zSig' does not have to be normalized. +| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the double-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat64Sign( float64 a ) +{ + + return float64_val(a)>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal double-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper double-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat64' except that `zSig' does not have to be normalized. +| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal extended double-precision floating-point value +| represented by the denormalized significand `aSig'. The normalized exponent +| and significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>48 ) & 0x7FFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the quadruple-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat128Sign( float128 a ) +{ + + return a.high>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal quadruple-precision floating-point value +| represented by the denormalized significand formed by the concatenation of +| `aSig0' and `aSig1'. The normalized exponent is stored at the location +| pointed to by `zExpPtr'. The most significant 49 bits of the normalized +| significand are stored at the location pointed to by `zSig0Ptr', and the +| least significant 64 bits of the normalized significand are stored at the +| location pointed to by `zSig1Ptr'. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat128Subnormal( + bits64 aSig0, + bits64 aSig1, + int32 *zExpPtr, + bits64 *zSig0Ptr, + bits64 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros64( aSig1 ) - 15; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 63 ); + } + else { + *zSig0Ptr = aSig1< 0, 0x95 - shiftCount, a< 0, 0x9C - shiftCount, a STATUS_VAR ); + } +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the 64-bit two's complement integer `a' +| to the double-precision floating-point format. The conversion is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 int64_to_float64( int64 a STATUS_PARAM ) +{ + flag zSign; + + if ( a == 0 ) return float64_zero; + if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) { + return packFloat64( 1, 0x43E, 0 ); + } + zSign = ( a < 0 ); + return normalizeRoundAndPackFloat64( zSign, 0x43C, zSign ? - a : a STATUS_VAR ); + +} + +float64 uint64_to_float64( uint64 a STATUS_PARAM ) +{ + if ( a == 0 ) return float64_zero; + return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the 64-bit two's complement integer `a' +| to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 int64_to_floatx80( int64 a STATUS_PARAM ) +{ + flag zSign; + uint64 absA; + int8 shiftCount; + + if ( a == 0 ) return packFloatx80( 0, 0, 0 ); + zSign = ( a < 0 ); + absA = zSign ? - a : a; + shiftCount = countLeadingZeros64( absA ); + return packFloatx80( zSign, 0x403E - shiftCount, absA<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64, aSigExtra; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = 0xBE - aExp; + if ( shiftCount < 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + if ( aExp ) aSig |= 0x00800000; + aSig64 = aSig; + aSig64 <<= 40; + shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra ); + return roundAndPackInt64( aSign, aSig64, aSigExtra STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64; + int64 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0xBE; + if ( 0 <= shiftCount ) { + if ( float32_val(a) != 0xDF000000 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig64 = aSig | 0x00800000; + aSig64 <<= 40; + z = aSig64>>( - shiftCount ); + if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float32_to_float64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR )); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float32_to_float128( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the single-precision floating-point value `a' to an integer, and +| returns the result as a single-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + bits32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return make_float32(aSign ? 0xBF800000 : 0); + case float_round_up: + return make_float32(aSign ? 0x80000000 : 0x3F800000); + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = float32_val(a); + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact; + return make_float32(z); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the single-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + } + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the single- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the single-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_add( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign STATUS_VAR); + } + else { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sub( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_mul( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the single-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_div( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the single-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_rem( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sqrt( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return float32_zero; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0x7FFFFFFF; + goto roundAndPack; + } + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + shift32RightJamming( zSig, 1, &zSig ); + roundAndPack: + return roundAndPackFloat32( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the binary log of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float32 float32_log2( float32 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits32 aSig, zSig, i; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); + return a; + } + + aExp -= 0x7F; + aSig |= 0x00800000; + zSign = aExp < 0; + zSig = aExp << 23; + + for (i = 1 << 22; i > 0; i >>= 1) { + aSig = ( (bits64)aSig * aSig ) >> 23; + if ( aSig & 0x01000000 ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + + return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq( float32 a, float32 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( float32_val(a) == float32_val(b) ) || + ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_le( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_lt( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +{ + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. +| If `a' is a NaN, the largest positive integer is returned. Otherwise, if +| the conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( 0x41E < aExp ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x433 - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the single-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float64_to_float32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + bits32 zSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 22, &aSig ); + zSig = aSig; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x381; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +| half-precision floating-point value, returning the result. After being +| shifted into the proper positions, the three fields are simply added +| together to form the result. This means that any integer portion of `zSig' +| will be added into the exponent. Since a properly normalized significand +| will have an integer portion equal to 1, the `zExp' input should be 1 less +| than the desired result exponent whenever `zSig' is a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ +static bits16 packFloat16(flag zSign, int16 zExp, bits16 zSig) +{ + return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig; +} + +/* Half precision floats come in two formats: standard IEEE and "ARM" format. + The latter gains extra exponent range by omitting the NaN/Inf encodings. */ + +float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSign = a >> 15; + aExp = (a >> 10) & 0x1f; + aSig = a & 0x3ff; + + if (aExp == 0x1f && ieee) { + if (aSig) { + /* Make sure correct exceptions are raised. */ + float32ToCommonNaN(a STATUS_VAR); + aSig |= 0x200; + } + return packFloat32(aSign, 0xff, aSig << 13); + } + if (aExp == 0) { + int8 shiftCount; + + if (aSig == 0) { + return packFloat32(aSign, 0, 0); + } + + shiftCount = countLeadingZeros32( aSig ) - 21; + aSig = aSig << shiftCount; + aExp = -shiftCount; + } + return packFloat32( aSign, aExp + 0x70, aSig << 13); +} + +bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) +{ + flag aSign; + int16 aExp; + bits32 aSig; + bits32 mask; + bits32 increment; + int8 roundingMode; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if (aSig) { + /* Make sure correct exceptions are raised. */ + float32ToCommonNaN(a STATUS_VAR); + aSig |= 0x00400000; + } + return packFloat16(aSign, 0x1f, aSig >> 13); + } + if (aExp == 0 && aSign == 0) { + return packFloat16(aSign, 0, 0); + } + /* Decimal point between bits 22 and 23. */ + aSig |= 0x00800000; + aExp -= 0x7f; + if (aExp < -14) { + mask = 0x007fffff; + if (aExp < -24) { + aExp = -25; + } else { + mask >>= 24 + aExp; + } + } else { + mask = 0x00001fff; + } + if (aSig & mask) { + float_raise( float_flag_underflow STATUS_VAR ); + roundingMode = STATUS(float_rounding_mode); + switch (roundingMode) { + case float_round_nearest_even: + increment = (mask + 1) >> 1; + if ((aSig & mask) == increment) { + increment = aSig & (increment << 1); + } + break; + case float_round_up: + increment = aSign ? 0 : mask; + break; + case float_round_down: + increment = aSign ? mask : 0; + break; + default: /* round_to_zero */ + increment = 0; + break; + } + aSig += increment; + if (aSig >= 0x01000000) { + aSig >>= 1; + aExp++; + } + } else if (aExp < -14 + && STATUS(float_detect_tininess) == float_tininess_before_rounding) { + float_raise( float_flag_underflow STATUS_VAR); + } + + if (ieee) { + if (aExp > 15) { + float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + return packFloat16(aSign, 0x1f, 0); + } + } else { + if (aExp > 16) { + float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + return packFloat16(aSign, 0x1f, 0x3ff); + } + } + if (aExp < -24) { + return packFloat16(aSign, 0, 0); + } + if (aExp < -14) { + aSig >>= -14 - aExp; + aExp = -14; + } + return packFloat16(aSign, aExp + 14, aSig >> 13); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + return + packFloatx80( + aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the quadruple-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float64_to_float128( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + shift128Right( aSig, 0, 4, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the double-precision floating-point value `a' to an integer, and +| returns the result as a double-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + bits64 z; + + aExp = extractFloat64Exp( a ); + if ( 0x433 <= aExp ) { + if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FF ) { + if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat64Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) { + return packFloat64( aSign, 0x3FF, 0 ); + } + break; + case float_round_down: + return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); + case float_round_up: + return make_float64( + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 )); + } + return packFloat64( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x433 - aExp; + roundBitsMask = lastBitMask - 1; + z = float64_val(a); + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != float64_val(a) ) + STATUS(float_exception_flags) |= float_flag_inexact; + return make_float64(z); + +} + +float64 float64_trunc_to_int( float64 a STATUS_PARAM) +{ + int oldmode; + float64 res; + oldmode = STATUS(float_rounding_mode); + STATUS(float_rounding_mode) = float_round_to_zero; + res = float64_round_to_int(a STATUS_VAR); + STATUS(float_rounding_mode) = oldmode; + return res; +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the double-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + } + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the double-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_add( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sub( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_mul( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the double-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_div( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the double-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_rem( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sqrt( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig, doubleZSig; + bits64 rem0, rem1, term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return float64_zero; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 ); + if ( ( zSig & 0x1FF ) <= 5 ) { + doubleZSig = zSig<<1; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + doubleZSig -= 2; + add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + return roundAndPackFloat64( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the binary log of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float64 float64_log2( float64 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits64 aSig, aSig0, aSig1, zSig, i; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR ); + return a; + } + + aExp -= 0x3FF; + aSig |= LIT64( 0x0010000000000000 ); + zSign = aExp < 0; + zSig = (bits64)aExp << 52; + for (i = 1LL << 51; i > 0; i >>= 1) { + mul64To128( aSig, aSig, &aSig0, &aSig1 ); + aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 ); + if ( aSig & LIT64( 0x0020000000000000 ) ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_eq( float64 a, float64 b STATUS_PARAM ) +{ + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_le( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_lt( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +{ + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic---which means in particular that the conversion +| is rounded according to the current rounding mode. If `a' is a NaN, the +| largest positive integer is returned. Otherwise, if the conversion +| overflows, the largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic, except that the conversion is always rounded +| toward zero. If `a' is a NaN, the largest positive integer is returned. +| Otherwise, if the conversion overflows, the largest integer with the same +| sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + shiftCount = 0x403E - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the single-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 33, &aSig ); + if ( aExp || aSig ) aExp -= 0x3F81; + return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig, zSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shift64RightJamming( aSig, 1, &zSig ); + if ( aExp || aSig ) aExp -= 0x3C01; + return roundAndPackFloat64( aSign, aExp, zSig STATUS_VAR ); + +} + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the quadruple-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the extended double-precision floating-point value `a' to an integer, +| and returns the result as an extended quadruple-precision floating-point +| value. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + floatx80 z; + + aExp = extractFloatx80Exp( a ); + if ( 0x403E <= aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FFF ) { + if ( ( aExp == 0 ) + && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + return a; + } + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloatx80Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) + ) { + return + packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + break; + case float_round_down: + return + aSign ? + packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) ) + : packFloatx80( 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloatx80( 1, 0, 0 ) + : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + return packFloatx80( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x403E - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.low += lastBitMask>>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the extended double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the sum is +| negated before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + zSig0 = aSig + bSig; + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the extended +| double-precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the extended double-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the extended double-precision floating-point +| value `a' by the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the extended double-precision floating-point +| value `a'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= doubleZSig0; + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), 0, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than or equal to the corresponding value `b', and 0 otherwise. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +| do not cause an exception. Otherwise, the comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +| an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; + if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x4028 - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); + return roundAndPackInt32( aSign, aSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1, savedASig; + int32 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + aSig0 |= ( aSig1 != 0 ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig0 ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig0 |= LIT64( 0x0001000000000000 ); + shiftCount = 0x402F - aExp; + savedASig = aSig0; + aSig0 >>= shiftCount; + z = aSig0; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); + if ( (bits64) ( aSig1<>( - shiftCount ); + if ( aSig1 + || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the single-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float128_to_float32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + bits32 zSig; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + aSig0 |= ( aSig1 != 0 ); + shift64RightJamming( aSig0, 18, &aSig0 ); + zSig = aSig0; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x3F81; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float128_to_float64( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + aSig0 |= ( aSig1 != 0 ); + if ( aExp || aSig0 ) { + aSig0 |= LIT64( 0x4000000000000000 ); + aExp -= 0x3C01; + } + return roundAndPackFloat64( aSign, aExp, aSig0 STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the extended double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 ); + return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 STATUS_VAR ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the quadruple-precision floating-point value `a' to an integer, and +| returns the result as a quadruple-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_round_to_int( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + float128 z; + + aExp = extractFloat128Exp( a ); + if ( 0x402F <= aExp ) { + if ( 0x406F <= aExp ) { + if ( ( aExp == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) + ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } + return a; + } + lastBitMask = 1; + lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + if ( lastBitMask ) { + add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits64) z.low < 0 ) { + ++z.high; + if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp < 0x3FFF ) { + if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat128Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) + && ( extractFloat128Frac0( a ) + | extractFloat128Frac1( a ) ) + ) { + return packFloat128( aSign, 0x3FFF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) + : packFloat128( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat128( 1, 0, 0, 0 ) + : packFloat128( 0, 0x3FFF, 0, 0 ); + } + return packFloat128( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x402F - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the quadruple-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int32 expDiff; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + return a; + } + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + return packFloat128( zSign, 0, zSig0, zSig1 ); + } + zSig2 = 0; + zSig0 |= LIT64( 0x0002000000000000 ); + zExp = aExp; + goto shiftRight1; + } + aSig0 |= LIT64( 0x0001000000000000 ); + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; + ++zExp; + shiftRight1: + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the quadruple- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int32 expDiff; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat128( STATUS(float_rounding_mode) == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= LIT64( 0x4000000000000000 ); + bBigger: + sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= LIT64( 0x4000000000000000 ); + aBigger: + sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the quadruple-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_add( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sub( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_mul( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x4000; + aSig0 |= LIT64( 0x0001000000000000 ); + shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); + mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the quadruple-precision floating-point value +| `a' by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_div( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FFD; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { + shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); + mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 4 ) { + mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the quadruple-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_rem( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; + bits64 allZero, alternateASig0, alternateASig1, sigMean1; + sbits64 sigMean0; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), + aSig1, + 15 - ( expDiff < 0 ), + &aSig0, + &aSig1 + ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + q = le128( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); + shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); + sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 61; + } + if ( -64 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + expDiff += 52; + if ( expDiff < 0 ) { + shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits64) aSig0 ); + add128( + aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits64) aSig0 < 0 ); + if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the quadruple-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sqrt( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; + aSig0 |= LIT64( 0x0001000000000000 ); + zSig0 = estimateSqrt32( aExp, aSig0>>17 ); + shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & 0x1FFF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_eq( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_le( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_lt( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_le_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +/* misc functions */ +float32 uint32_to_float32( unsigned int a STATUS_PARAM ) +{ + return int64_to_float32(a STATUS_VAR); +} + +float64 uint32_to_float64( unsigned int a STATUS_PARAM ) +{ + return int64_to_float64(a STATUS_VAR); +} + +unsigned int float32_to_uint32( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +/* FIXME: This looks broken. */ +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + +#define COMPARE(s, nan_exp) \ +INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ + int is_quiet STATUS_PARAM ) \ +{ \ + flag aSign, bSign; \ + bits ## s av, bv; \ + \ + if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ + extractFloat ## s ## Frac( a ) ) || \ + ( ( extractFloat ## s ## Exp( b ) == nan_exp ) && \ + extractFloat ## s ## Frac( b ) )) { \ + if (!is_quiet || \ + float ## s ## _is_signaling_nan( a ) || \ + float ## s ## _is_signaling_nan( b ) ) { \ + float_raise( float_flag_invalid STATUS_VAR); \ + } \ + return float_relation_unordered; \ + } \ + aSign = extractFloat ## s ## Sign( a ); \ + bSign = extractFloat ## s ## Sign( b ); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ + if ( aSign != bSign ) { \ + if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ + /* zero case */ \ + return float_relation_equal; \ + } else { \ + return 1 - (2 * aSign); \ + } \ + } else { \ + if (av == bv) { \ + return float_relation_equal; \ + } else { \ + return 1 - 2 * (aSign ^ ( av < bv )); \ + } \ + } \ +} \ + \ +int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \ +} \ + \ +int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \ +} + +COMPARE(32, 0xff) +COMPARE(64, 0x7ff) + +INLINE int float128_compare_internal( float128 a, float128 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloat128Exp( a ) == 0x7fff ) && + ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || + ( ( extractFloat128Exp( b ) == 0x7fff ) && + ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) { + if (!is_quiet || + float128_is_signaling_nan( a ) || + float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int float128_compare( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 0 STATUS_VAR); +} + +int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 1 STATUS_VAR); +} + +/* Multiply A by 2 raised to the power N. */ +float32 float32_scalbn( float32 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0xFF ) { + return a; + } + if ( aExp != 0 ) + aSig |= 0x00800000; + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 7; + return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); +} + +float64 float64_scalbn( float64 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + if ( aExp != 0 ) + aSig |= LIT64( 0x0010000000000000 ); + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 10; + return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); +} + +#ifdef FLOATX80 +floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + if (aExp == 0 && aSig == 0) + return a; + + aExp += n; + return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), + aSign, aExp, aSig, 0 STATUS_VAR ); +} +#endif + +#ifdef FLOAT128 +float128 float128_scalbn( float128 a, int n STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + return a; + } + if ( aExp != 0 ) + aSig0 |= LIT64( 0x0001000000000000 ); + else if ( aSig0 == 0 && aSig1 == 0 ) + return a; + + aExp += n - 1; + return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 + STATUS_VAR ); + +} +#endif diff --git a/qemu/qemu-git/fpu/.svn/text-base/softfloat.h.svn-base b/qemu/qemu-git/fpu/.svn/text-base/softfloat.h.svn-base new file mode 100644 index 0000000..9d82694 --- /dev/null +++ b/qemu/qemu-git/fpu/.svn/text-base/softfloat.h.svn-base @@ -0,0 +1,527 @@ +/*============================================================================ + +This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#ifndef SOFTFLOAT_H +#define SOFTFLOAT_H + +#if defined(CONFIG_SOLARIS) && defined(CONFIG_NEEDS_LIBSUNMATH) +#include +#endif + +#include +#include "config.h" + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines the most convenient type that holds +| integers of at least as many bits as specified. For example, `uint8' should +| be the most convenient type that can hold unsigned integers of as many as +| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most +| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +| to the same as `int'. +*----------------------------------------------------------------------------*/ +typedef uint8_t flag; +typedef uint8_t uint8; +typedef int8_t int8; +#ifndef _AIX +typedef int uint16; +typedef int int16; +#endif +typedef unsigned int uint32; +typedef signed int int32; +typedef uint64_t uint64; +typedef int64_t int64; + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines a type that holds integers +| of _exactly_ the number of bits specified. For instance, for most +| implementation of C, `bits16' and `sbits16' should be `typedef'ed to +| `unsigned short int' and `signed short int' (or `short int'), respectively. +*----------------------------------------------------------------------------*/ +typedef uint8_t bits8; +typedef int8_t sbits8; +typedef uint16_t bits16; +typedef int16_t sbits16; +typedef uint32_t bits32; +typedef int32_t sbits32; +typedef uint64_t bits64; +typedef int64_t sbits64; + +#define LIT64( a ) a##LL +#define INLINE static inline + +/*---------------------------------------------------------------------------- +| The macro `FLOATX80' must be defined to enable the extended double-precision +| floating-point format `floatx80'. If this macro is not defined, the +| `floatx80' type will not be defined, and none of the functions that either +| input or output the `floatx80' type will be defined. The same applies to +| the `FLOAT128' macro and the quadruple-precision format `float128'. +*----------------------------------------------------------------------------*/ +#ifdef CONFIG_SOFTFLOAT +/* bit exact soft float support */ +#define FLOATX80 +#define FLOAT128 +#else +/* native float support */ +#if (defined(__i386__) || defined(__x86_64__)) && !defined(CONFIG_BSD) +#define FLOATX80 +#endif +#endif /* !CONFIG_SOFTFLOAT */ + +#define STATUS_PARAM , float_status *status +#define STATUS(field) status->field +#define STATUS_VAR , status + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point ordering relations +*----------------------------------------------------------------------------*/ +enum { + float_relation_less = -1, + float_relation_equal = 0, + float_relation_greater = 1, + float_relation_unordered = 2 +}; + +#ifdef CONFIG_SOFTFLOAT +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point types. +*----------------------------------------------------------------------------*/ +/* Use structures for soft-float types. This prevents accidentally mixing + them with native int/float types. A sufficiently clever compiler and + sane ABI should be able to see though these structs. However + x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */ +//#define USE_SOFTFLOAT_STRUCT_TYPES +#ifdef USE_SOFTFLOAT_STRUCT_TYPES +typedef struct { + uint32_t v; +} float32; +/* The cast ensures an error if the wrong type is passed. */ +#define float32_val(x) (((float32)(x)).v) +#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +typedef struct { + uint64_t v; +} float64; +#define float64_val(x) (((float64)(x)).v) +#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#else +typedef uint32_t float32; +typedef uint64_t float64; +#define float32_val(x) (x) +#define float64_val(x) (x) +#define make_float32(x) (x) +#define make_float64(x) (x) +#endif +#ifdef FLOATX80 +typedef struct { + uint64_t low; + uint16_t high; +} floatx80; +#endif +#ifdef FLOAT128 +typedef struct { +#ifdef HOST_WORDS_BIGENDIAN + uint64_t high, low; +#else + uint64_t low, high; +#endif +} float128; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point underflow tininess-detection mode. +*----------------------------------------------------------------------------*/ +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point exception flags. +*----------------------------------------------------------------------------*/ +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 4, + float_flag_overflow = 8, + float_flag_underflow = 16, + float_flag_inexact = 32 +}; + +typedef struct float_status { + signed char float_detect_tininess; + signed char float_rounding_mode; + signed char float_exception_flags; + signed char float_exception_mask; +#ifdef FLOATX80 + signed char floatx80_rounding_precision; +#endif + flag flush_to_zero; + flag default_nan_mode; +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_flush_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_to_zero) = val; +} +INLINE void set_default_nan_mode(flag val STATUS_PARAM) +{ + STATUS(default_nan_mode) = val; +} +INLINE int get_float_exception_flags(float_status *status) +{ + return STATUS(float_exception_flags); +} +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Routine to raise any or all of the software IEC/IEEE floating-point +| exception flags. +*----------------------------------------------------------------------------*/ +void float_raise( int8 flags STATUS_PARAM); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM ); +float64 int32_to_float64( int STATUS_PARAM ); +float32 uint32_to_float32( unsigned int STATUS_PARAM ); +float64 uint32_to_float64( unsigned int STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM ); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM ); +float32 uint64_to_float32( uint64_t STATUS_PARAM ); +float64 int64_to_float64( int64_t STATUS_PARAM ); +float64 uint64_to_float64( uint64_t STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software half-precision conversion routines. +*----------------------------------------------------------------------------*/ +bits16 float32_to_float16( float32, flag STATUS_PARAM ); +float32 float16_to_float32( bits16, flag STATUS_PARAM ); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM ); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM ); +unsigned int float32_to_uint32( float32 STATUS_PARAM ); +unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); +int64_t float32_to_int64( float32 STATUS_PARAM ); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM ); +float64 float32_to_float64( float32 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM ); +float32 float32_add( float32, float32 STATUS_PARAM ); +float32 float32_sub( float32, float32 STATUS_PARAM ); +float32 float32_mul( float32, float32 STATUS_PARAM ); +float32 float32_div( float32, float32 STATUS_PARAM ); +float32 float32_rem( float32, float32 STATUS_PARAM ); +float32 float32_sqrt( float32 STATUS_PARAM ); +float32 float32_log2( float32 STATUS_PARAM ); +int float32_eq( float32, float32 STATUS_PARAM ); +int float32_le( float32, float32 STATUS_PARAM ); +int float32_lt( float32, float32 STATUS_PARAM ); +int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_le_quiet( float32, float32 STATUS_PARAM ); +int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_nan( float32 ); +int float32_is_signaling_nan( float32 ); +float32 float32_scalbn( float32, int STATUS_PARAM ); + +INLINE float32 float32_abs(float32 a) +{ + return make_float32(float32_val(a) & 0x7fffffff); +} + +INLINE float32 float32_chs(float32 a) +{ + return make_float32(float32_val(a) ^ 0x80000000); +} + +INLINE int float32_is_infinity(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0x7f800000; +} + +INLINE int float32_is_neg(float32 a) +{ + return float32_val(a) >> 31; +} + +INLINE int float32_is_zero(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0; +} + +#define float32_zero make_float32(0) +#define float32_one make_float32(0x3f800000) + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64 (float64 a STATUS_PARAM); +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); +float64 float64_add( float64, float64 STATUS_PARAM ); +float64 float64_sub( float64, float64 STATUS_PARAM ); +float64 float64_mul( float64, float64 STATUS_PARAM ); +float64 float64_div( float64, float64 STATUS_PARAM ); +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +float64 float64_log2( float64 STATUS_PARAM ); +int float64_eq( float64, float64 STATUS_PARAM ); +int float64_le( float64, float64 STATUS_PARAM ); +int float64_lt( float64, float64 STATUS_PARAM ); +int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_le_quiet( float64, float64 STATUS_PARAM ); +int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_nan( float64 a ); +int float64_is_signaling_nan( float64 ); +float64 float64_scalbn( float64, int STATUS_PARAM ); + +INLINE float64 float64_abs(float64 a) +{ + return make_float64(float64_val(a) & 0x7fffffffffffffffLL); +} + +INLINE float64 float64_chs(float64 a) +{ + return make_float64(float64_val(a) ^ 0x8000000000000000LL); +} + +INLINE int float64_is_infinity(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL; +} + +INLINE int float64_is_neg(float64 a) +{ + return float64_val(a) >> 63; +} + +INLINE int float64_is_zero(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL) == 0; +} + +#define float64_zero make_float64(0) +#define float64_one make_float64(0x3ff0000000000000LL) + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM ); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_nan( floatx80 ); +int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); + +INLINE floatx80 floatx80_abs(floatx80 a) +{ + a.high &= 0x7fff; + return a; +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + a.high ^= 0x8000; + return a; +} + +INLINE int floatx80_is_infinity(floatx80 a) +{ + return (a.high & 0x7fff) == 0x7fff && a.low == 0; +} + +INLINE int floatx80_is_neg(floatx80 a) +{ + return a.high >> 15; +} + +INLINE int floatx80_is_zero(floatx80 a) +{ + return (a.high & 0x7fff) == 0 && a.low == 0; +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float128_to_int32( float128 STATUS_PARAM ); +int float128_to_int32_round_to_zero( float128 STATUS_PARAM ); +int64_t float128_to_int64( float128 STATUS_PARAM ); +int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM ); +float32 float128_to_float32( float128 STATUS_PARAM ); +float64 float128_to_float64( float128 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float128_to_floatx80( float128 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision operations. +*----------------------------------------------------------------------------*/ +float128 float128_round_to_int( float128 STATUS_PARAM ); +float128 float128_add( float128, float128 STATUS_PARAM ); +float128 float128_sub( float128, float128 STATUS_PARAM ); +float128 float128_mul( float128, float128 STATUS_PARAM ); +float128 float128_div( float128, float128 STATUS_PARAM ); +float128 float128_rem( float128, float128 STATUS_PARAM ); +float128 float128_sqrt( float128 STATUS_PARAM ); +int float128_eq( float128, float128 STATUS_PARAM ); +int float128_le( float128, float128 STATUS_PARAM ); +int float128_lt( float128, float128 STATUS_PARAM ); +int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_le_quiet( float128, float128 STATUS_PARAM ); +int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_compare( float128, float128 STATUS_PARAM ); +int float128_compare_quiet( float128, float128 STATUS_PARAM ); +int float128_is_nan( float128 ); +int float128_is_signaling_nan( float128 ); +float128 float128_scalbn( float128, int STATUS_PARAM ); + +INLINE float128 float128_abs(float128 a) +{ + a.high &= 0x7fffffffffffffffLL; + return a; +} + +INLINE float128 float128_chs(float128 a) +{ + a.high ^= 0x8000000000000000LL; + return a; +} + +INLINE int float128_is_infinity(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0; +} + +INLINE int float128_is_neg(float128 a) +{ + return a.high >> 63; +} + +INLINE int float128_is_zero(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; +} + +#endif + +#else /* CONFIG_SOFTFLOAT */ + +#include "softfloat-native.h" + +#endif /* !CONFIG_SOFTFLOAT */ + +#endif /* !SOFTFLOAT_H */ diff --git a/qemu/qemu-git/fpu/softfloat-macros.h b/qemu/qemu-git/fpu/softfloat-macros.h new file mode 100644 index 0000000..7838228 --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat-macros.h @@ -0,0 +1,719 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 32, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 64, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +| _plus_ the number of bits given in `count'. The shifted result is at most +| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +| bits shifted off form a second 64-bit result as follows: The _last_ bit +| shifted off is the most-significant bit of the extra result, and the other +| 63 bits of the extra result are all zero if and only if _all_but_the_last_ +| bits shifted off were all zero. This extra result is stored in the location +| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. +| (This routine makes more sense if `a0' and `a1' are considered to form +| a fixed-point value with binary point between `a0' and `a1'. This fixed- +| point value is shifted right by the number of bits given in `count', and +| the integer part of the result is returned at the location pointed to by +| `z0Ptr'. The fractional part of the result may be slightly corrupted as +| described above, and is returned at the location pointed to by `z1Ptr'.) +*----------------------------------------------------------------------------*/ + +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' can be arbitrarily large; in particular, if `count' is greater +| than 128, the result will be 0. The result is broken into two 64-bit pieces +| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. If any nonzero bits are shifted off, they +| are ``jammed'' into the least significant bit of the result by setting the +| least significant bit to 1. The value of `count' can be arbitrarily large; +| in particular, if `count' is greater than 128, the result will be either +| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or +| nonzero. The result is broken into two 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 64. The result is broken into two 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/*---------------------------------------------------------------------------- +| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +| by the number of bits given in `count'. Any bits shifted off are lost. +| The value of `count' must be less than 64. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +| any carry out is lost. The result is broken into two 64-bit pieces which +| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/*---------------------------------------------------------------------------- +| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +| modulo 2^192, so any carry out is lost. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +| 2^128, so any borrow out (carry out) is lost. The result is broken into two +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +| `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +| from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +| result is broken into three 64-bit pieces which are stored at the locations +| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +| into two 64-bit pieces which are stored at the locations pointed to by +| `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by +| `b' to obtain a 192-bit product. The product is broken into three 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +| `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +| product. The product is broken into four 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the 64-bit integer quotient obtained by dividing +| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The +| divisor `b' must be at least 2^63. If q is the exact quotient truncated +| toward zero, the approximation returned lies between q and q + 2 inclusive. +| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +| unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the square root of the 32-bit significand given +| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +| `aExp' (the least significant bit) is 1, the integer returned approximates +| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +| case, the approximation returned lies strictly within +/-2 of the exact +| value. +*----------------------------------------------------------------------------*/ + +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 32 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 64 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +| is equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +| not equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} diff --git a/qemu/qemu-git/fpu/softfloat-native.c b/qemu/qemu-git/fpu/softfloat-native.c new file mode 100644 index 0000000..8d64f4e --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat-native.c @@ -0,0 +1,534 @@ +/* Native implementation of soft float functions. Only a single status + context is supported */ +#include "softfloat.h" +#include +#if defined(CONFIG_SOLARIS) +#include +#endif + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) || \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) + fpsetround(val); +#elif defined(__arm__) + /* nothing to do */ +#else + fesetround(val); +#endif +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +#if defined(CONFIG_BSD) || \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#define lrintf(f) ((int32_t)rint(f)) +#define llrintf(f) ((int64_t)rint(f)) +#define sqrtf(f) ((float)sqrt(f)) +#define remainderf(fa, fb) ((float)remainder(fa, fb)) +#define rintf(f) ((float)rint(f)) +#if !defined(__sparc__) && \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +extern long double rintl(long double); +extern long double scalbnl(long double, int); + +long long +llrintl(long double x) { + return ((long long) rintl(x)); +} + +long +lrintl(long double x) { + return ((long) rintl(x)); +} + +long double +ldexpl(long double x, int n) { + return (scalbnl(x, n)); +} +#endif +#endif + +#if defined(_ARCH_PPC) + +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +static double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} + +#define rint qemu_rint +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32(int v STATUS_PARAM) +{ + return (float32)v; +} + +float32 uint32_to_float32(unsigned int v STATUS_PARAM) +{ + return (float32)v; +} + +float64 int32_to_float64(int v STATUS_PARAM) +{ + return (float64)v; +} + +float64 uint32_to_float64(unsigned int v STATUS_PARAM) +{ + return (float64)v; +} + +#ifdef FLOATX80 +floatx80 int32_to_floatx80(int v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif +float32 int64_to_float32( int64_t v STATUS_PARAM) +{ + return (float32)v; +} +float32 uint64_to_float32( uint64_t v STATUS_PARAM) +{ + return (float32)v; +} +float64 int64_to_float64( int64_t v STATUS_PARAM) +{ + return (float64)v; +} +float64 uint64_to_float64( uint64_t v STATUS_PARAM) +{ + return (float64)v; +} +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif + +/* XXX: this code implements the x86 behaviour, not the IEEE one. */ +#if HOST_LONG_BITS == 32 +static inline int long_to_int32(long a) +{ + return a; +} +#else +static inline int long_to_int32(long a) +{ + if (a != (int32_t)a) + a = 0x80000000; + return a; +} +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 a STATUS_PARAM) +{ + return long_to_int32(lrintf(a)); +} +int float32_to_int32_round_to_zero( float32 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float32_to_int64( float32 a STATUS_PARAM) +{ + return llrintf(a); +} + +int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM) +{ + return (int64_t)a; +} + +float64 float32_to_float64( float32 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 a STATUS_PARAM) +{ + return a; +} +#endif + +unsigned int float32_to_uint32( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrintf(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + return rintf(a); +} + +float32 float32_rem( float32 a, float32 b STATUS_PARAM) +{ + return remainderf(a, b); +} + +float32 float32_sqrt( float32 a STATUS_PARAM) +{ + return sqrtf(a); +} +int float32_compare( float32 a, float32 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float32_is_signaling_nan( float32 a1) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +} + +int float32_is_nan( float32 a1 ) +{ + float32u u; + uint64_t a; + u.f = a1; + a = u.i; + return ( 0xFF800000 < ( a<<1 ) ); +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 a STATUS_PARAM) +{ + return long_to_int32(lrint(a)); +} +int float64_to_int32_round_to_zero( float64 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float64_to_int64( float64 a STATUS_PARAM) +{ + return llrint(a); +} +int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 float64_to_float32( float64 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 a STATUS_PARAM) +{ + return a; +} +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 a STATUS_PARAM) +{ + return a; +} +#endif + +unsigned int float64_to_uint32( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrint(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = llrint(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = (int64_t)(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +#if defined(__sun__) && \ + (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10) +static inline float64 trunc(float64 x) +{ + return x < 0 ? -floor(-x) : floor(x); +} +#endif +float64 float64_trunc_to_int( float64 a STATUS_PARAM ) +{ + return trunc(a); +} + +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ +#if defined(__arm__) + switch(STATUS(float_rounding_mode)) { + default: + case float_round_nearest_even: + asm("rndd %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_down: + asm("rnddm %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_up: + asm("rnddp %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_to_zero: + asm("rnddz %0, %1" : "=f" (a) : "f"(a)); + break; + } +#else + return rint(a); +#endif +} + +float64 float64_rem( float64 a, float64 b STATUS_PARAM) +{ + return remainder(a, b); +} + +float64 float64_sqrt( float64 a STATUS_PARAM) +{ + return sqrt(a); +} +int float64_compare( float64 a, float64 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int float64_is_signaling_nan( float64 a1) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +int float64_is_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 a STATUS_PARAM) +{ + return long_to_int32(lrintl(a)); +} +int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int)a; +} +int64_t floatx80_to_int64( floatx80 a STATUS_PARAM) +{ + return llrintl(a); +} +int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 floatx80_to_float32( floatx80 a STATUS_PARAM) +{ + return a; +} +float64 floatx80_to_float64( floatx80 a STATUS_PARAM) +{ + return a; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM) +{ + return rintl(a); +} +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM) +{ + return remainderl(a, b); +} +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) +{ + return sqrtl(a); +} +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (a < b) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (a > b) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return float_relation_less; + } else if (a == b) { + return float_relation_equal; + } else if (isgreater(a, b)) { + return float_relation_greater; + } else { + return float_relation_unordered; + } +} +int floatx80_is_signaling_nan( floatx80 a1) +{ + floatx80u u; + uint64_t aLow; + u.f = a1; + + aLow = u.i.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( u.i.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( u.i.low == aLow ); +} + +int floatx80_is_nan( floatx80 a1 ) +{ + floatx80u u; + u.f = a1; + return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 ); +} + +#endif diff --git a/qemu/qemu-git/fpu/softfloat-native.h b/qemu/qemu-git/fpu/softfloat-native.h new file mode 100644 index 0000000..fe737b3 --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat-native.h @@ -0,0 +1,499 @@ +/* Native implementation of soft float functions */ +#include + +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \ + || defined(CONFIG_SOLARIS) +#include +#define fabsf(f) ((float)fabs(f)) +#else +#include +#endif + +#if defined(__OpenBSD__) || defined(__NetBSD__) +#include +#endif + +/* + * Define some C99-7.12.3 classification macros and + * some C99-.12.4 for Solaris systems OS less than 10, + * or Solaris 10 systems running GCC 3.x or less. + * Solaris 10 with GCC4 does not need these macros as they + * are defined in with a compiler directive + */ +#if defined(CONFIG_SOLARIS) && \ + ((CONFIG_SOLARIS_VERSION <= 9 ) || \ + ((CONFIG_SOLARIS_VERSION == 10) && (__GNUC__ < 4))) \ + || (defined(__OpenBSD__) && (OpenBSD < 200811)) +/* + * C99 7.12.3 classification macros + * and + * C99 7.12.14 comparison macros + * + * ... do not work on Solaris 10 using GNU CC 3.4.x. + * Try to workaround the missing / broken C99 math macros. + */ +#if defined(__OpenBSD__) +#define unordered(x, y) (isnan(x) || isnan(y)) +#endif + +#ifdef __NetBSD__ +#ifndef isgreater +#define isgreater(x, y) __builtin_isgreater(x, y) +#endif +#ifndef isgreaterequal +#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y) +#endif +#ifndef isless +#define isless(x, y) __builtin_isless(x, y) +#endif +#ifndef islessequal +#define islessequal(x, y) __builtin_islessequal(x, y) +#endif +#ifndef isunordered +#define isunordered(x, y) __builtin_isunordered(x, y) +#endif +#endif + + +#define isnormal(x) (fpclass(x) >= FP_NZERO) +#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) +#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y))) +#define isless(x, y) ((!unordered(x, y)) && ((x) < (y))) +#define islessequal(x, y) ((!unordered(x, y)) && ((x) <= (y))) +#define isunordered(x,y) unordered(x, y) +#endif + +#if defined(__sun__) && !defined(CONFIG_NEEDS_LIBSUNMATH) + +#ifndef isnan +# define isnan(x) \ + (sizeof (x) == sizeof (long double) ? isnan_ld (x) \ + : sizeof (x) == sizeof (double) ? isnan_d (x) \ + : isnan_f (x)) +static inline int isnan_f (float x) { return x != x; } +static inline int isnan_d (double x) { return x != x; } +static inline int isnan_ld (long double x) { return x != x; } +#endif + +#ifndef isinf +# define isinf(x) \ + (sizeof (x) == sizeof (long double) ? isinf_ld (x) \ + : sizeof (x) == sizeof (double) ? isinf_d (x) \ + : isinf_f (x)) +static inline int isinf_f (float x) { return isnan (x - x); } +static inline int isinf_d (double x) { return isnan (x - x); } +static inline int isinf_ld (long double x) { return isnan (x - x); } +#endif +#endif + +typedef float float32; +typedef double float64; +#ifdef FLOATX80 +typedef long double floatx80; +#endif + +typedef union { + float32 f; + uint32_t i; +} float32u; +typedef union { + float64 f; + uint64_t i; +} float64u; +#ifdef FLOATX80 +typedef union { + floatx80 f; + struct { + uint64_t low; + uint16_t high; + } i; +} floatx80u; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \ + || defined(CONFIG_SOLARIS) +#if defined(__OpenBSD__) +#define FE_RM FP_RM +#define FE_RP FP_RP +#define FE_RZ FP_RZ +#endif +enum { + float_round_nearest_even = FP_RN, + float_round_down = FP_RM, + float_round_up = FP_RP, + float_round_to_zero = FP_RZ +}; +#elif defined(__arm__) +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; +#else +enum { + float_round_nearest_even = FE_TONEAREST, + float_round_down = FE_DOWNWARD, + float_round_up = FE_UPWARD, + float_round_to_zero = FE_TOWARDZERO +}; +#endif + +typedef struct float_status { + int float_rounding_mode; +#ifdef FLOATX80 + int floatx80_rounding_precision; +#endif +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM); +float32 uint32_to_float32( unsigned int STATUS_PARAM); +float64 int32_to_float64( int STATUS_PARAM); +float64 uint32_to_float64( unsigned int STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM); +float32 uint64_to_float32( uint64_t STATUS_PARAM); +float64 int64_to_float64( int64_t STATUS_PARAM); +float64 uint64_to_float64( uint64_t v STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM); +unsigned int float32_to_uint32( float32 a STATUS_PARAM); +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM); +int64_t float32_to_int64( float32 STATUS_PARAM); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM); +float64 float32_to_float64( float32 STATUS_PARAM); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM); +INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM) +{ + return a + b; +} +INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM) +{ + return a - b; +} +INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM) +{ + return a * b; +} +INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) +{ + return a / b; +} +float32 float32_rem( float32, float32 STATUS_PARAM); +float32 float32_sqrt( float32 STATUS_PARAM); +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) +{ + return a == b; +} +INLINE int float32_le( float32 a, float32 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) +{ + return a < b; +} +INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isless(a, b); +} +INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_signaling_nan( float32 ); +int float32_is_nan( float32 ); + +INLINE float32 float32_abs(float32 a) +{ + return fabsf(a); +} + +INLINE float32 float32_chs(float32 a) +{ + return -a; +} + +INLINE float32 float32_is_infinity(float32 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float32 float32_is_neg(float32 a) +{ + float32u u; + u.f = a; + return u.i >> 31; +} + +INLINE float32 float32_is_zero(float32 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE float32 float32_scalbn(float32 a, int n) +{ + return scalbnf(a, n); +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64( float64 STATUS_PARAM ); +uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM ); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); +INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM) +{ + return a + b; +} +INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM) +{ + return a - b; +} +INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM) +{ + return a * b; +} +INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) +{ + return a / b; +} +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) +{ + return a == b; +} +INLINE int float64_le( float64 a, float64 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) +{ + return a < b; +} +INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isless(a, b); + +} +INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_signaling_nan( float64 ); +int float64_is_nan( float64 ); + +INLINE float64 float64_abs(float64 a) +{ + return fabs(a); +} + +INLINE float64 float64_chs(float64 a) +{ + return -a; +} + +INLINE float64 float64_is_infinity(float64 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float64 float64_is_neg(float64 a) +{ + float64u u; + u.f = a; + return u.i >> 63; +} + +INLINE float64 float64_is_zero(float64 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE float64 float64_scalbn(float64 a, int n) +{ + return scalbn(a, n); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a + b; +} +INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a - b; +} +INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a * b; +} +INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a / b; +} +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a == b; +} +INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a <= b; +} +INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a < b; +} +INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a <= b && a >= b; +} +INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isless(a, b); + +} +INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_signaling_nan( floatx80 ); +int floatx80_is_nan( floatx80 ); + +INLINE floatx80 floatx80_abs(floatx80 a) +{ + return fabsl(a); +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + return -a; +} + +INLINE floatx80 floatx80_is_infinity(floatx80 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE floatx80 floatx80_is_neg(floatx80 a) +{ + floatx80u u; + u.f = a; + return u.i.high >> 15; +} + +INLINE floatx80 floatx80_is_zero(floatx80 a) +{ + return fpclassify(a) == FP_ZERO; +} + +INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +{ + return scalbnl(a, n); +} + +#endif diff --git a/qemu/qemu-git/fpu/softfloat-specialize.h b/qemu/qemu-git/fpu/softfloat-specialize.h new file mode 100644 index 0000000..8e6aceb --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat-specialize.h @@ -0,0 +1,581 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define SNAN_BIT_IS_ONE 1 +#else +#define SNAN_BIT_IS_ONE 0 +#endif + +/*---------------------------------------------------------------------------- +| Raises the exceptions specified by `flags'. Floating-point traps can be +| defined here if desired. It is currently not possible for such a trap +| to substitute a result value. If traps are not implemented, this routine +| should be simply `float_exception_flags |= flags;'. +*----------------------------------------------------------------------------*/ + +void float_raise( int8 flags STATUS_PARAM ) +{ + STATUS(float_exception_flags) |= flags; +} + +/*---------------------------------------------------------------------------- +| Internal canonical NaN format. +*----------------------------------------------------------------------------*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float32_default_nan make_float32(0x7FFFFFFF) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float32_default_nan make_float32(0x7FC00000) +#elif defined(TARGET_HPPA) +#define float32_default_nan make_float32(0x7FA00000) +#elif SNAN_BIT_IS_ONE +#define float32_default_nan make_float32(0x7FBFFFFF) +#else +#define float32_default_nan make_float32(0xFFC00000) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float32_is_nan( float32 a_ ) +{ + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#else + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float32_is_signaling_nan( float32 a_ ) +{ + uint32_t a = float32_val(a_); +#if SNAN_BIT_IS_ONE + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#else + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); + z.sign = float32_val(a)>>31; + z.low = 0; + z.high = ( (bits64) float32_val(a) )<<41; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the single- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float32 commonNaNToFloat32( commonNaNT a ) +{ + bits32 mantissa = a.high>>41; + if ( mantissa ) + return make_float32( + ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); + else + return float32_default_nan; +} + +/*---------------------------------------------------------------------------- +| Takes two single-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits32 av, bv, res; + + if ( STATUS(default_nan_mode) ) + return float32_default_nan; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + av = float32_val(a); + bv = float32_val(b); +#if SNAN_BIT_IS_ONE + av &= ~0x00400000; + bv &= ~0x00400000; +#else + av |= 0x00400000; + bv |= 0x00400000; +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + res = bIsNaN ? bv : av; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) + res = av; + else { + returnLargerSignificand: + if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) + res = bv; + else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } + } + else { + res = bv; + } + return make_float32(res); +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) +#elif defined(TARGET_HPPA) +#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) +#elif SNAN_BIT_IS_ONE +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) +#else +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float64_is_nan( float64 a_ ) +{ + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#else + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float64_is_signaling_nan( float64 a_ ) +{ + bits64 a = float64_val(a_); +#if SNAN_BIT_IS_ONE + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#else + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = float64_val(a)>>63; + z.low = 0; + z.high = float64_val(a)<<12; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the double- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float64 commonNaNToFloat64( commonNaNT a ) +{ + bits64 mantissa = a.high>>12; + + if ( mantissa ) + return make_float64( + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF0000000000000 ) + | ( a.high>>12 )); + else + return float64_default_nan; +} + +/*---------------------------------------------------------------------------- +| Takes two double-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits64 av, bv, res; + + if ( STATUS(default_nan_mode) ) + return float64_default_nan; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + av = float64_val(a); + bv = float64_val(b); +#if SNAN_BIT_IS_ONE + av &= ~LIT64( 0x0008000000000000 ); + bv &= ~LIT64( 0x0008000000000000 ); +#else + av |= LIT64( 0x0008000000000000 ); + bv |= LIT64( 0x0008000000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + res = bIsNaN ? bv : av; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) + res = av; + else { + returnLargerSignificand: + if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) + res = bv; + else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } + } + else { + res = bv; + } + return make_float64(res); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. The +| `high' and `low' values hold the most- and least-significant bits, +| respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define floatx80_default_nan_high 0x7FFF +#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) +#else +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xC000000000000000 ) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| quiet NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int floatx80_is_nan( floatx80 a ) +{ +#if SNAN_BIT_IS_ONE + bits64 aLow; + + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#else + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int floatx80_is_signaling_nan( floatx80 a ) +{ +#if SNAN_BIT_IS_ONE + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#else + bits64 aLow; + + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +| invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the extended +| double-precision floating-point format. +*----------------------------------------------------------------------------*/ + +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + if (a.high) + z.low = a.high; + else + z.low = floatx80_default_nan_low; + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; +} + +/*---------------------------------------------------------------------------- +| Takes two extended double-precision floating-point values `a' and `b', one +| of which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + if ( STATUS(default_nan_mode) ) { + a.low = floatx80_default_nan_low; + a.high = floatx80_default_nan_high; + return a; + } + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.low &= ~LIT64( 0xC000000000000000 ); + b.low &= ~LIT64( 0xC000000000000000 ); +#else + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) return a; + returnLargerSignificand: + if ( a.low < b.low ) return b; + if ( b.low < a.low ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated quadruple-precision NaN. The `high' and +| `low' values hold the most- and least-significant bits, respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) +#else +#define float128_default_nan_high LIT64( 0xFFFF800000000000 ) +#define float128_default_nan_low LIT64( 0x0000000000000000 ) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float128_is_nan( float128 a ) +{ +#if SNAN_BIT_IS_ONE + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#else + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float128_is_signaling_nan( float128 a ) +{ +#if SNAN_BIT_IS_ONE + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#else + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>63; + shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the quadruple- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float128 commonNaNToFloat128( commonNaNT a ) +{ + float128 z; + + shift128Right( a.high, a.low, 16, &z.high, &z.low ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); + return z; +} + +/*---------------------------------------------------------------------------- +| Takes two quadruple-precision floating-point values `a' and `b', one of +| which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + if ( STATUS(default_nan_mode) ) { + a.low = float128_default_nan_low; + a.high = float128_default_nan_high; + return a; + } + + aIsNaN = float128_is_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsNaN = float128_is_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.high &= ~LIT64( 0x0000800000000000 ); + b.high &= ~LIT64( 0x0000800000000000 ); +#else + a.high |= LIT64( 0x0000800000000000 ); + b.high |= LIT64( 0x0000800000000000 ); +#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN || ! bIsNaN ) return a; + returnLargerSignificand: + if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b; + if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } +} + +#endif diff --git a/qemu/qemu-git/fpu/softfloat.c b/qemu/qemu-git/fpu/softfloat.c new file mode 100644 index 0000000..395f9b1 --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat.c @@ -0,0 +1,5808 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also + be flushed to zero. */ +#include "softfloat.h" + +/*---------------------------------------------------------------------------- +| Primitive arithmetic functions, including multi-word arithmetic, and +| division and square root approximations. (Can be specialized to target if +| desired.) +*----------------------------------------------------------------------------*/ +#include "softfloat-macros.h" + +/*---------------------------------------------------------------------------- +| Functions and definitions to determine: (1) whether tininess for underflow +| is detected before or after rounding by default, (2) what (if anything) +| happens when exceptions are raised, (3) how signaling NaNs are distinguished +| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +| are propagated from function inputs to output. These details are target- +| specific. +*----------------------------------------------------------------------------*/ +#include "softfloat-specialize.h" + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +} + +void set_float_exception_flags(int val STATUS_PARAM) +{ + STATUS(float_exception_flags) = val; +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +/*---------------------------------------------------------------------------- +| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +| and 7, and returns the properly rounded 32-bit integer corresponding to the +| input. If `zSign' is 1, the input is negated before being converted to an +| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input +| is simply rounded to an integer, with the inexact exception raised if the +| input cannot be represented exactly as an integer. However, if the fixed- +| point input is too large, the invalid exception is raised and the largest +| positive or negative integer is returned. +*----------------------------------------------------------------------------*/ + +static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_raise( float_flag_invalid STATUS_VAR); + return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and +| `absZ1', with binary point between bits 63 and 64 (between the input words), +| and returns the properly rounded 64-bit integer corresponding to the input. +| If `zSign' is 1, the input is negated before being converted to an integer. +| Ordinarily, the fixed-point input is simply rounded to an integer, with +| the inexact exception raised if the input cannot be represented exactly as +| an integer. However, if the fixed-point input is too large, the invalid +| exception is raised and the largest positive or negative integer is +| returned. +*----------------------------------------------------------------------------*/ + +static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven, increment; + int64 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + increment = ( (sbits64) absZ1 < 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + increment = 0; + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && absZ1; + } + else { + increment = ( roundingMode == float_round_up ) && absZ1; + } + } + } + if ( increment ) { + ++absZ0; + if ( absZ0 == 0 ) goto overflow; + absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + } + z = absZ0; + if ( zSign ) z = - z; + if ( z && ( ( z < 0 ) ^ zSign ) ) { + overflow: + float_raise( float_flag_invalid STATUS_VAR); + return + zSign ? (sbits64) LIT64( 0x8000000000000000 ) + : LIT64( 0x7FFFFFFFFFFFFFFF ); + } + if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the fraction bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return float32_val(a) & 0x007FFFFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( float32_val(a)>>23 ) & 0xFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat32Sign( float32 a ) +{ + + return float32_val(a)>>31; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal single-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper single-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat32' except that `zSig' does not have to be normalized. +| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the double-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat64Sign( float64 a ) +{ + + return float64_val(a)>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal double-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper double-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat64' except that `zSig' does not have to be normalized. +| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal extended double-precision floating-point value +| represented by the denormalized significand `aSig'. The normalized exponent +| and significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>48 ) & 0x7FFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the quadruple-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat128Sign( float128 a ) +{ + + return a.high>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal quadruple-precision floating-point value +| represented by the denormalized significand formed by the concatenation of +| `aSig0' and `aSig1'. The normalized exponent is stored at the location +| pointed to by `zExpPtr'. The most significant 49 bits of the normalized +| significand are stored at the location pointed to by `zSig0Ptr', and the +| least significant 64 bits of the normalized significand are stored at the +| location pointed to by `zSig1Ptr'. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat128Subnormal( + bits64 aSig0, + bits64 aSig1, + int32 *zExpPtr, + bits64 *zSig0Ptr, + bits64 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros64( aSig1 ) - 15; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 63 ); + } + else { + *zSig0Ptr = aSig1< 0, 0x95 - shiftCount, a< 0, 0x9C - shiftCount, a STATUS_VAR ); + } +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the 64-bit two's complement integer `a' +| to the double-precision floating-point format. The conversion is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 int64_to_float64( int64 a STATUS_PARAM ) +{ + flag zSign; + + if ( a == 0 ) return float64_zero; + if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) { + return packFloat64( 1, 0x43E, 0 ); + } + zSign = ( a < 0 ); + return normalizeRoundAndPackFloat64( zSign, 0x43C, zSign ? - a : a STATUS_VAR ); + +} + +float64 uint64_to_float64( uint64 a STATUS_PARAM ) +{ + if ( a == 0 ) return float64_zero; + return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the 64-bit two's complement integer `a' +| to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 int64_to_floatx80( int64 a STATUS_PARAM ) +{ + flag zSign; + uint64 absA; + int8 shiftCount; + + if ( a == 0 ) return packFloatx80( 0, 0, 0 ); + zSign = ( a < 0 ); + absA = zSign ? - a : a; + shiftCount = countLeadingZeros64( absA ); + return packFloatx80( zSign, 0x403E - shiftCount, absA<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64, aSigExtra; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = 0xBE - aExp; + if ( shiftCount < 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + if ( aExp ) aSig |= 0x00800000; + aSig64 = aSig; + aSig64 <<= 40; + shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra ); + return roundAndPackInt64( aSign, aSig64, aSigExtra STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64; + int64 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0xBE; + if ( 0 <= shiftCount ) { + if ( float32_val(a) != 0xDF000000 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig64 = aSig | 0x00800000; + aSig64 <<= 40; + z = aSig64>>( - shiftCount ); + if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float32_to_float64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR )); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float32_to_float128( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the single-precision floating-point value `a' to an integer, and +| returns the result as a single-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + bits32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return make_float32(aSign ? 0xBF800000 : 0); + case float_round_up: + return make_float32(aSign ? 0x80000000 : 0x3F800000); + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = float32_val(a); + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact; + return make_float32(z); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the single-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + } + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the single- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the single-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_add( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign STATUS_VAR); + } + else { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sub( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_mul( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the single-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_div( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the single-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_rem( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sqrt( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return float32_zero; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0x7FFFFFFF; + goto roundAndPack; + } + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + shift32RightJamming( zSig, 1, &zSig ); + roundAndPack: + return roundAndPackFloat32( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the binary log of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float32 float32_log2( float32 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits32 aSig, zSig, i; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); + return a; + } + + aExp -= 0x7F; + aSig |= 0x00800000; + zSign = aExp < 0; + zSig = aExp << 23; + + for (i = 1 << 22; i > 0; i >>= 1) { + aSig = ( (bits64)aSig * aSig ) >> 23; + if ( aSig & 0x01000000 ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + + return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq( float32 a, float32 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( float32_val(a) == float32_val(b) ) || + ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_le( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_lt( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +{ + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits32 av, bv; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. +| If `a' is a NaN, the largest positive integer is returned. Otherwise, if +| the conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( 0x41E < aExp ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x433 - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the single-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float64_to_float32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + bits32 zSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 22, &aSig ); + zSig = aSig; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x381; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +| half-precision floating-point value, returning the result. After being +| shifted into the proper positions, the three fields are simply added +| together to form the result. This means that any integer portion of `zSig' +| will be added into the exponent. Since a properly normalized significand +| will have an integer portion equal to 1, the `zExp' input should be 1 less +| than the desired result exponent whenever `zSig' is a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ +static bits16 packFloat16(flag zSign, int16 zExp, bits16 zSig) +{ + return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig; +} + +/* Half precision floats come in two formats: standard IEEE and "ARM" format. + The latter gains extra exponent range by omitting the NaN/Inf encodings. */ + +float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSign = a >> 15; + aExp = (a >> 10) & 0x1f; + aSig = a & 0x3ff; + + if (aExp == 0x1f && ieee) { + if (aSig) { + /* Make sure correct exceptions are raised. */ + float32ToCommonNaN(a STATUS_VAR); + aSig |= 0x200; + } + return packFloat32(aSign, 0xff, aSig << 13); + } + if (aExp == 0) { + int8 shiftCount; + + if (aSig == 0) { + return packFloat32(aSign, 0, 0); + } + + shiftCount = countLeadingZeros32( aSig ) - 21; + aSig = aSig << shiftCount; + aExp = -shiftCount; + } + return packFloat32( aSign, aExp + 0x70, aSig << 13); +} + +bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) +{ + flag aSign; + int16 aExp; + bits32 aSig; + bits32 mask; + bits32 increment; + int8 roundingMode; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if (aSig) { + /* Make sure correct exceptions are raised. */ + float32ToCommonNaN(a STATUS_VAR); + aSig |= 0x00400000; + } + return packFloat16(aSign, 0x1f, aSig >> 13); + } + if (aExp == 0 && aSign == 0) { + return packFloat16(aSign, 0, 0); + } + /* Decimal point between bits 22 and 23. */ + aSig |= 0x00800000; + aExp -= 0x7f; + if (aExp < -14) { + mask = 0x007fffff; + if (aExp < -24) { + aExp = -25; + } else { + mask >>= 24 + aExp; + } + } else { + mask = 0x00001fff; + } + if (aSig & mask) { + float_raise( float_flag_underflow STATUS_VAR ); + roundingMode = STATUS(float_rounding_mode); + switch (roundingMode) { + case float_round_nearest_even: + increment = (mask + 1) >> 1; + if ((aSig & mask) == increment) { + increment = aSig & (increment << 1); + } + break; + case float_round_up: + increment = aSign ? 0 : mask; + break; + case float_round_down: + increment = aSign ? mask : 0; + break; + default: /* round_to_zero */ + increment = 0; + break; + } + aSig += increment; + if (aSig >= 0x01000000) { + aSig >>= 1; + aExp++; + } + } else if (aExp < -14 + && STATUS(float_detect_tininess) == float_tininess_before_rounding) { + float_raise( float_flag_underflow STATUS_VAR); + } + + if (ieee) { + if (aExp > 15) { + float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + return packFloat16(aSign, 0x1f, 0); + } + } else { + if (aExp > 16) { + float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + return packFloat16(aSign, 0x1f, 0x3ff); + } + } + if (aExp < -24) { + return packFloat16(aSign, 0, 0); + } + if (aExp < -14) { + aSig >>= -14 - aExp; + aExp = -14; + } + return packFloat16(aSign, aExp + 14, aSig >> 13); +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + return + packFloatx80( + aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the quadruple-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float64_to_float128( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + shift128Right( aSig, 0, 4, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the double-precision floating-point value `a' to an integer, and +| returns the result as a double-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + bits64 z; + + aExp = extractFloat64Exp( a ); + if ( 0x433 <= aExp ) { + if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FF ) { + if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat64Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) { + return packFloat64( aSign, 0x3FF, 0 ); + } + break; + case float_round_down: + return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); + case float_round_up: + return make_float64( + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 )); + } + return packFloat64( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x433 - aExp; + roundBitsMask = lastBitMask - 1; + z = float64_val(a); + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != float64_val(a) ) + STATUS(float_exception_flags) |= float_flag_inexact; + return make_float64(z); + +} + +float64 float64_trunc_to_int( float64 a STATUS_PARAM) +{ + int oldmode; + float64 res; + oldmode = STATUS(float_rounding_mode); + STATUS(float_rounding_mode) = float_round_to_zero; + res = float64_round_to_int(a STATUS_VAR); + STATUS(float_rounding_mode) = oldmode; + return res; +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the double-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + } + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the double-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_add( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sub( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_mul( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the double-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_div( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the double-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_rem( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sqrt( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig, doubleZSig; + bits64 rem0, rem1, term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return float64_zero; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 ); + if ( ( zSig & 0x1FF ) <= 5 ) { + doubleZSig = zSig<<1; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + doubleZSig -= 2; + add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + return roundAndPackFloat64( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the binary log of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float64 float64_log2( float64 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits64 aSig, aSig0, aSig1, zSig, i; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR ); + return a; + } + + aExp -= 0x3FF; + aSig |= LIT64( 0x0010000000000000 ); + zSign = aExp < 0; + zSig = (bits64)aExp << 52; + for (i = 1LL << 51; i > 0; i >>= 1) { + mul64To128( aSig, aSig, &aSig0, &aSig1 ); + aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 ); + if ( aSig & LIT64( 0x0020000000000000 ) ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_eq( float64 a, float64 b STATUS_PARAM ) +{ + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_le( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_lt( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +{ + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + av = float64_val(a); + bv = float64_val(b); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + bits64 av, bv; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + av = float64_val(a); + bv = float64_val(b); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic---which means in particular that the conversion +| is rounded according to the current rounding mode. If `a' is a NaN, the +| largest positive integer is returned. Otherwise, if the conversion +| overflows, the largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic, except that the conversion is always rounded +| toward zero. If `a' is a NaN, the largest positive integer is returned. +| Otherwise, if the conversion overflows, the largest integer with the same +| sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + shiftCount = 0x403E - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the single-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 33, &aSig ); + if ( aExp || aSig ) aExp -= 0x3F81; + return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig, zSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shift64RightJamming( aSig, 1, &zSig ); + if ( aExp || aSig ) aExp -= 0x3C01; + return roundAndPackFloat64( aSign, aExp, zSig STATUS_VAR ); + +} + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the quadruple-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the extended double-precision floating-point value `a' to an integer, +| and returns the result as an extended quadruple-precision floating-point +| value. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + floatx80 z; + + aExp = extractFloatx80Exp( a ); + if ( 0x403E <= aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FFF ) { + if ( ( aExp == 0 ) + && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + return a; + } + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloatx80Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) + ) { + return + packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + break; + case float_round_down: + return + aSign ? + packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) ) + : packFloatx80( 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloatx80( 1, 0, 0 ) + : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + return packFloatx80( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x403E - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.low += lastBitMask>>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the extended double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the sum is +| negated before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + zSig0 = aSig + bSig; + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the extended +| double-precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the extended double-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the extended double-precision floating-point +| value `a' by the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the extended double-precision floating-point +| value `a'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= doubleZSig0; + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), 0, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than or equal to the corresponding value `b', and 0 otherwise. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +| do not cause an exception. Otherwise, the comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +| an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; + if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x4028 - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); + return roundAndPackInt32( aSign, aSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1, savedASig; + int32 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + aSig0 |= ( aSig1 != 0 ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig0 ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig0 |= LIT64( 0x0001000000000000 ); + shiftCount = 0x402F - aExp; + savedASig = aSig0; + aSig0 >>= shiftCount; + z = aSig0; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); + if ( (bits64) ( aSig1<>( - shiftCount ); + if ( aSig1 + || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the single-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float128_to_float32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + bits32 zSig; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + aSig0 |= ( aSig1 != 0 ); + shift64RightJamming( aSig0, 18, &aSig0 ); + zSig = aSig0; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x3F81; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float128_to_float64( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + aSig0 |= ( aSig1 != 0 ); + if ( aExp || aSig0 ) { + aSig0 |= LIT64( 0x4000000000000000 ); + aExp -= 0x3C01; + } + return roundAndPackFloat64( aSign, aExp, aSig0 STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the extended double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 ); + return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 STATUS_VAR ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the quadruple-precision floating-point value `a' to an integer, and +| returns the result as a quadruple-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_round_to_int( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + float128 z; + + aExp = extractFloat128Exp( a ); + if ( 0x402F <= aExp ) { + if ( 0x406F <= aExp ) { + if ( ( aExp == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) + ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } + return a; + } + lastBitMask = 1; + lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + if ( lastBitMask ) { + add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits64) z.low < 0 ) { + ++z.high; + if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp < 0x3FFF ) { + if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat128Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) + && ( extractFloat128Frac0( a ) + | extractFloat128Frac1( a ) ) + ) { + return packFloat128( aSign, 0x3FFF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) + : packFloat128( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat128( 1, 0, 0, 0 ) + : packFloat128( 0, 0x3FFF, 0, 0 ); + } + return packFloat128( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x402F - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the quadruple-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int32 expDiff; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + return a; + } + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + return packFloat128( zSign, 0, zSig0, zSig1 ); + } + zSig2 = 0; + zSig0 |= LIT64( 0x0002000000000000 ); + zExp = aExp; + goto shiftRight1; + } + aSig0 |= LIT64( 0x0001000000000000 ); + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; + ++zExp; + shiftRight1: + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the quadruple- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int32 expDiff; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat128( STATUS(float_rounding_mode) == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= LIT64( 0x4000000000000000 ); + bBigger: + sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= LIT64( 0x4000000000000000 ); + aBigger: + sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the quadruple-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_add( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sub( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_mul( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x4000; + aSig0 |= LIT64( 0x0001000000000000 ); + shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); + mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the quadruple-precision floating-point value +| `a' by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_div( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FFD; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { + shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); + mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 4 ) { + mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the quadruple-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_rem( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; + bits64 allZero, alternateASig0, alternateASig1, sigMean1; + sbits64 sigMean0; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), + aSig1, + 15 - ( expDiff < 0 ), + &aSig0, + &aSig1 + ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + q = le128( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); + shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); + sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 61; + } + if ( -64 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + expDiff += 52; + if ( expDiff < 0 ) { + shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits64) aSig0 ); + add128( + aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits64) aSig0 < 0 ); + if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the quadruple-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sqrt( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; + aSig0 |= LIT64( 0x0001000000000000 ); + zSig0 = estimateSqrt32( aExp, aSig0>>17 ); + shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & 0x1FFF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_eq( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_le( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_lt( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_le_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +/* misc functions */ +float32 uint32_to_float32( unsigned int a STATUS_PARAM ) +{ + return int64_to_float32(a STATUS_VAR); +} + +float64 uint32_to_float64( unsigned int a STATUS_PARAM ) +{ + return int64_to_float64(a STATUS_VAR); +} + +unsigned int float32_to_uint32( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +/* FIXME: This looks broken. */ +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR); + + return v - INT64_MIN; +} + +#define COMPARE(s, nan_exp) \ +INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ + int is_quiet STATUS_PARAM ) \ +{ \ + flag aSign, bSign; \ + bits ## s av, bv; \ + \ + if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ + extractFloat ## s ## Frac( a ) ) || \ + ( ( extractFloat ## s ## Exp( b ) == nan_exp ) && \ + extractFloat ## s ## Frac( b ) )) { \ + if (!is_quiet || \ + float ## s ## _is_signaling_nan( a ) || \ + float ## s ## _is_signaling_nan( b ) ) { \ + float_raise( float_flag_invalid STATUS_VAR); \ + } \ + return float_relation_unordered; \ + } \ + aSign = extractFloat ## s ## Sign( a ); \ + bSign = extractFloat ## s ## Sign( b ); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ + if ( aSign != bSign ) { \ + if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ + /* zero case */ \ + return float_relation_equal; \ + } else { \ + return 1 - (2 * aSign); \ + } \ + } else { \ + if (av == bv) { \ + return float_relation_equal; \ + } else { \ + return 1 - 2 * (aSign ^ ( av < bv )); \ + } \ + } \ +} \ + \ +int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \ +} \ + \ +int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \ +} + +COMPARE(32, 0xff) +COMPARE(64, 0x7ff) + +INLINE int float128_compare_internal( float128 a, float128 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloat128Exp( a ) == 0x7fff ) && + ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || + ( ( extractFloat128Exp( b ) == 0x7fff ) && + ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) { + if (!is_quiet || + float128_is_signaling_nan( a ) || + float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int float128_compare( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 0 STATUS_VAR); +} + +int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 1 STATUS_VAR); +} + +/* Multiply A by 2 raised to the power N. */ +float32 float32_scalbn( float32 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0xFF ) { + return a; + } + if ( aExp != 0 ) + aSig |= 0x00800000; + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 7; + return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); +} + +float64 float64_scalbn( float64 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + if ( aExp != 0 ) + aSig |= LIT64( 0x0010000000000000 ); + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 10; + return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); +} + +#ifdef FLOATX80 +floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + if (aExp == 0 && aSig == 0) + return a; + + aExp += n; + return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), + aSign, aExp, aSig, 0 STATUS_VAR ); +} +#endif + +#ifdef FLOAT128 +float128 float128_scalbn( float128 a, int n STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + return a; + } + if ( aExp != 0 ) + aSig0 |= LIT64( 0x0001000000000000 ); + else if ( aSig0 == 0 && aSig1 == 0 ) + return a; + + aExp += n - 1; + return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 + STATUS_VAR ); + +} +#endif diff --git a/qemu/qemu-git/fpu/softfloat.h b/qemu/qemu-git/fpu/softfloat.h new file mode 100644 index 0000000..9d82694 --- /dev/null +++ b/qemu/qemu-git/fpu/softfloat.h @@ -0,0 +1,527 @@ +/*============================================================================ + +This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#ifndef SOFTFLOAT_H +#define SOFTFLOAT_H + +#if defined(CONFIG_SOLARIS) && defined(CONFIG_NEEDS_LIBSUNMATH) +#include +#endif + +#include +#include "config.h" + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines the most convenient type that holds +| integers of at least as many bits as specified. For example, `uint8' should +| be the most convenient type that can hold unsigned integers of as many as +| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most +| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +| to the same as `int'. +*----------------------------------------------------------------------------*/ +typedef uint8_t flag; +typedef uint8_t uint8; +typedef int8_t int8; +#ifndef _AIX +typedef int uint16; +typedef int int16; +#endif +typedef unsigned int uint32; +typedef signed int int32; +typedef uint64_t uint64; +typedef int64_t int64; + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines a type that holds integers +| of _exactly_ the number of bits specified. For instance, for most +| implementation of C, `bits16' and `sbits16' should be `typedef'ed to +| `unsigned short int' and `signed short int' (or `short int'), respectively. +*----------------------------------------------------------------------------*/ +typedef uint8_t bits8; +typedef int8_t sbits8; +typedef uint16_t bits16; +typedef int16_t sbits16; +typedef uint32_t bits32; +typedef int32_t sbits32; +typedef uint64_t bits64; +typedef int64_t sbits64; + +#define LIT64( a ) a##LL +#define INLINE static inline + +/*---------------------------------------------------------------------------- +| The macro `FLOATX80' must be defined to enable the extended double-precision +| floating-point format `floatx80'. If this macro is not defined, the +| `floatx80' type will not be defined, and none of the functions that either +| input or output the `floatx80' type will be defined. The same applies to +| the `FLOAT128' macro and the quadruple-precision format `float128'. +*----------------------------------------------------------------------------*/ +#ifdef CONFIG_SOFTFLOAT +/* bit exact soft float support */ +#define FLOATX80 +#define FLOAT128 +#else +/* native float support */ +#if (defined(__i386__) || defined(__x86_64__)) && !defined(CONFIG_BSD) +#define FLOATX80 +#endif +#endif /* !CONFIG_SOFTFLOAT */ + +#define STATUS_PARAM , float_status *status +#define STATUS(field) status->field +#define STATUS_VAR , status + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point ordering relations +*----------------------------------------------------------------------------*/ +enum { + float_relation_less = -1, + float_relation_equal = 0, + float_relation_greater = 1, + float_relation_unordered = 2 +}; + +#ifdef CONFIG_SOFTFLOAT +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point types. +*----------------------------------------------------------------------------*/ +/* Use structures for soft-float types. This prevents accidentally mixing + them with native int/float types. A sufficiently clever compiler and + sane ABI should be able to see though these structs. However + x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */ +//#define USE_SOFTFLOAT_STRUCT_TYPES +#ifdef USE_SOFTFLOAT_STRUCT_TYPES +typedef struct { + uint32_t v; +} float32; +/* The cast ensures an error if the wrong type is passed. */ +#define float32_val(x) (((float32)(x)).v) +#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +typedef struct { + uint64_t v; +} float64; +#define float64_val(x) (((float64)(x)).v) +#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#else +typedef uint32_t float32; +typedef uint64_t float64; +#define float32_val(x) (x) +#define float64_val(x) (x) +#define make_float32(x) (x) +#define make_float64(x) (x) +#endif +#ifdef FLOATX80 +typedef struct { + uint64_t low; + uint16_t high; +} floatx80; +#endif +#ifdef FLOAT128 +typedef struct { +#ifdef HOST_WORDS_BIGENDIAN + uint64_t high, low; +#else + uint64_t low, high; +#endif +} float128; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point underflow tininess-detection mode. +*----------------------------------------------------------------------------*/ +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point exception flags. +*----------------------------------------------------------------------------*/ +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 4, + float_flag_overflow = 8, + float_flag_underflow = 16, + float_flag_inexact = 32 +}; + +typedef struct float_status { + signed char float_detect_tininess; + signed char float_rounding_mode; + signed char float_exception_flags; + signed char float_exception_mask; +#ifdef FLOATX80 + signed char floatx80_rounding_precision; +#endif + flag flush_to_zero; + flag default_nan_mode; +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_flush_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_to_zero) = val; +} +INLINE void set_default_nan_mode(flag val STATUS_PARAM) +{ + STATUS(default_nan_mode) = val; +} +INLINE int get_float_exception_flags(float_status *status) +{ + return STATUS(float_exception_flags); +} +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Routine to raise any or all of the software IEC/IEEE floating-point +| exception flags. +*----------------------------------------------------------------------------*/ +void float_raise( int8 flags STATUS_PARAM); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM ); +float64 int32_to_float64( int STATUS_PARAM ); +float32 uint32_to_float32( unsigned int STATUS_PARAM ); +float64 uint32_to_float64( unsigned int STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM ); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM ); +float32 uint64_to_float32( uint64_t STATUS_PARAM ); +float64 int64_to_float64( int64_t STATUS_PARAM ); +float64 uint64_to_float64( uint64_t STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software half-precision conversion routines. +*----------------------------------------------------------------------------*/ +bits16 float32_to_float16( float32, flag STATUS_PARAM ); +float32 float16_to_float32( bits16, flag STATUS_PARAM ); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM ); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM ); +unsigned int float32_to_uint32( float32 STATUS_PARAM ); +unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); +int64_t float32_to_int64( float32 STATUS_PARAM ); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM ); +float64 float32_to_float64( float32 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM ); +float32 float32_add( float32, float32 STATUS_PARAM ); +float32 float32_sub( float32, float32 STATUS_PARAM ); +float32 float32_mul( float32, float32 STATUS_PARAM ); +float32 float32_div( float32, float32 STATUS_PARAM ); +float32 float32_rem( float32, float32 STATUS_PARAM ); +float32 float32_sqrt( float32 STATUS_PARAM ); +float32 float32_log2( float32 STATUS_PARAM ); +int float32_eq( float32, float32 STATUS_PARAM ); +int float32_le( float32, float32 STATUS_PARAM ); +int float32_lt( float32, float32 STATUS_PARAM ); +int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_le_quiet( float32, float32 STATUS_PARAM ); +int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_nan( float32 ); +int float32_is_signaling_nan( float32 ); +float32 float32_scalbn( float32, int STATUS_PARAM ); + +INLINE float32 float32_abs(float32 a) +{ + return make_float32(float32_val(a) & 0x7fffffff); +} + +INLINE float32 float32_chs(float32 a) +{ + return make_float32(float32_val(a) ^ 0x80000000); +} + +INLINE int float32_is_infinity(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0x7f800000; +} + +INLINE int float32_is_neg(float32 a) +{ + return float32_val(a) >> 31; +} + +INLINE int float32_is_zero(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0; +} + +#define float32_zero make_float32(0) +#define float32_one make_float32(0x3f800000) + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64 (float64 a STATUS_PARAM); +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); +float64 float64_add( float64, float64 STATUS_PARAM ); +float64 float64_sub( float64, float64 STATUS_PARAM ); +float64 float64_mul( float64, float64 STATUS_PARAM ); +float64 float64_div( float64, float64 STATUS_PARAM ); +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +float64 float64_log2( float64 STATUS_PARAM ); +int float64_eq( float64, float64 STATUS_PARAM ); +int float64_le( float64, float64 STATUS_PARAM ); +int float64_lt( float64, float64 STATUS_PARAM ); +int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_le_quiet( float64, float64 STATUS_PARAM ); +int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_nan( float64 a ); +int float64_is_signaling_nan( float64 ); +float64 float64_scalbn( float64, int STATUS_PARAM ); + +INLINE float64 float64_abs(float64 a) +{ + return make_float64(float64_val(a) & 0x7fffffffffffffffLL); +} + +INLINE float64 float64_chs(float64 a) +{ + return make_float64(float64_val(a) ^ 0x8000000000000000LL); +} + +INLINE int float64_is_infinity(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL; +} + +INLINE int float64_is_neg(float64 a) +{ + return float64_val(a) >> 63; +} + +INLINE int float64_is_zero(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL) == 0; +} + +#define float64_zero make_float64(0) +#define float64_one make_float64(0x3ff0000000000000LL) + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM ); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_nan( floatx80 ); +int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); + +INLINE floatx80 floatx80_abs(floatx80 a) +{ + a.high &= 0x7fff; + return a; +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + a.high ^= 0x8000; + return a; +} + +INLINE int floatx80_is_infinity(floatx80 a) +{ + return (a.high & 0x7fff) == 0x7fff && a.low == 0; +} + +INLINE int floatx80_is_neg(floatx80 a) +{ + return a.high >> 15; +} + +INLINE int floatx80_is_zero(floatx80 a) +{ + return (a.high & 0x7fff) == 0 && a.low == 0; +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float128_to_int32( float128 STATUS_PARAM ); +int float128_to_int32_round_to_zero( float128 STATUS_PARAM ); +int64_t float128_to_int64( float128 STATUS_PARAM ); +int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM ); +float32 float128_to_float32( float128 STATUS_PARAM ); +float64 float128_to_float64( float128 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float128_to_floatx80( float128 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision operations. +*----------------------------------------------------------------------------*/ +float128 float128_round_to_int( float128 STATUS_PARAM ); +float128 float128_add( float128, float128 STATUS_PARAM ); +float128 float128_sub( float128, float128 STATUS_PARAM ); +float128 float128_mul( float128, float128 STATUS_PARAM ); +float128 float128_div( float128, float128 STATUS_PARAM ); +float128 float128_rem( float128, float128 STATUS_PARAM ); +float128 float128_sqrt( float128 STATUS_PARAM ); +int float128_eq( float128, float128 STATUS_PARAM ); +int float128_le( float128, float128 STATUS_PARAM ); +int float128_lt( float128, float128 STATUS_PARAM ); +int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_le_quiet( float128, float128 STATUS_PARAM ); +int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_compare( float128, float128 STATUS_PARAM ); +int float128_compare_quiet( float128, float128 STATUS_PARAM ); +int float128_is_nan( float128 ); +int float128_is_signaling_nan( float128 ); +float128 float128_scalbn( float128, int STATUS_PARAM ); + +INLINE float128 float128_abs(float128 a) +{ + a.high &= 0x7fffffffffffffffLL; + return a; +} + +INLINE float128 float128_chs(float128 a) +{ + a.high ^= 0x8000000000000000LL; + return a; +} + +INLINE int float128_is_infinity(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0; +} + +INLINE int float128_is_neg(float128 a) +{ + return a.high >> 63; +} + +INLINE int float128_is_zero(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; +} + +#endif + +#else /* CONFIG_SOFTFLOAT */ + +#include "softfloat-native.h" + +#endif /* !CONFIG_SOFTFLOAT */ + +#endif /* !SOFTFLOAT_H */ diff --git a/qemu/qemu-git/gdb-xml/.svn/all-wcprops b/qemu/qemu-git/gdb-xml/.svn/all-wcprops new file mode 100644 index 0000000..3deb7a5 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/all-wcprops @@ -0,0 +1,29 @@ +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdb-xml +END +arm-core.xml +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdb-xml/arm-core.xml +END +arm-vfp.xml +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdb-xml/arm-vfp.xml +END +arm-vfp3.xml +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdb-xml/arm-vfp3.xml +END +arm-neon.xml +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/gdb-xml/arm-neon.xml +END diff --git a/qemu/qemu-git/gdb-xml/.svn/entries b/qemu/qemu-git/gdb-xml/.svn/entries new file mode 100644 index 0000000..42aa63d --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/entries @@ -0,0 +1,164 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/gdb-xml +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +arm-core.xml +file + + + + +2013-08-23T00:54:47.000000Z +23d23037148c271f0a1126b1409e1b60 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1133 + +arm-vfp.xml +file + + + + +2013-08-23T00:54:47.000000Z +a38e09f5adb8bdf9e996fa72d96344d0 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1270 + +arm-vfp3.xml +file + + + + +2013-08-23T00:54:47.000000Z +472bdb85a675fd422d5cfcaa78d47401 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2006 + +arm-neon.xml +file + + + + +2013-08-23T00:54:47.000000Z +1010436f3430cb50b3038ab3a5fbbbbe +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3960 + diff --git a/qemu/qemu-git/gdb-xml/.svn/text-base/arm-core.xml.svn-base b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-core.xml.svn-base new file mode 100644 index 0000000..6012f34 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-core.xml.svn-base @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/.svn/text-base/arm-neon.xml.svn-base b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-neon.xml.svn-base new file mode 100644 index 0000000..ce3ee03 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-neon.xml.svn-base @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp.xml.svn-base b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp.xml.svn-base new file mode 100644 index 0000000..b20881e --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp.xml.svn-base @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp3.xml.svn-base b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp3.xml.svn-base new file mode 100644 index 0000000..227afd8 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/.svn/text-base/arm-vfp3.xml.svn-base @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/arm-core.xml b/qemu/qemu-git/gdb-xml/arm-core.xml new file mode 100644 index 0000000..6012f34 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/arm-core.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/arm-neon.xml b/qemu/qemu-git/gdb-xml/arm-neon.xml new file mode 100644 index 0000000..ce3ee03 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/arm-neon.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/arm-vfp.xml b/qemu/qemu-git/gdb-xml/arm-vfp.xml new file mode 100644 index 0000000..b20881e --- /dev/null +++ b/qemu/qemu-git/gdb-xml/arm-vfp.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdb-xml/arm-vfp3.xml b/qemu/qemu-git/gdb-xml/arm-vfp3.xml new file mode 100644 index 0000000..227afd8 --- /dev/null +++ b/qemu/qemu-git/gdb-xml/arm-vfp3.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qemu/qemu-git/gdbstub.h b/qemu/qemu-git/gdbstub.h new file mode 100644 index 0000000..5740041 --- /dev/null +++ b/qemu/qemu-git/gdbstub.h @@ -0,0 +1,35 @@ +#ifndef GDBSTUB_H +#define GDBSTUB_H + +#define DEFAULT_GDBSTUB_PORT "1234" + +/* GDB breakpoint/watchpoint types */ +#define GDB_BREAKPOINT_SW 0 +#define GDB_BREAKPOINT_HW 1 +#define GDB_WATCHPOINT_WRITE 2 +#define GDB_WATCHPOINT_READ 3 +#define GDB_WATCHPOINT_ACCESS 4 + +typedef void (*gdb_syscall_complete_cb)(CPUState *env, + target_ulong ret, target_ulong err); + +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); +int use_gdb_syscalls(void); +void gdb_set_stop_cpu(CPUState *env); +#ifdef CONFIG_USER_ONLY +int gdb_queuesig (void); +int gdb_handlesig (CPUState *, int); +void gdb_exit(CPUState *, int); +void gdb_signalled(CPUState *, int); +int gdbserver_start(int); +void gdbserver_fork(CPUState *); +#else +int gdbserver_start(const char *port); +#endif +/* Get or set a register. Returns the size of the register. */ +typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg); +void gdb_register_coprocessor(CPUState *env, + gdb_reg_cb get_reg, gdb_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); + +#endif diff --git a/qemu/qemu-git/gen-icount.h b/qemu/qemu-git/gen-icount.h new file mode 100644 index 0000000..3268f72 --- /dev/null +++ b/qemu/qemu-git/gen-icount.h @@ -0,0 +1,46 @@ +/* Helpers for instruction counting code generation. */ + +static TCGArg *icount_arg; +static int icount_label; + +static inline void gen_icount_start(void) +{ + TCGv_i32 count; + + if (!use_icount) + return; + + icount_label = gen_new_label(); + count = tcg_temp_local_new_i32(); + tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32)); + /* This is a horrid hack to allow fixing up the value later. */ + icount_arg = gen_opparam_ptr + 1; + tcg_gen_subi_i32(count, count, 0xdeadbeef); + + tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label); + tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low)); + tcg_temp_free_i32(count); +} + +static void gen_icount_end(TranslationBlock *tb, int num_insns) +{ + if (use_icount) { + *icount_arg = num_insns; + gen_set_label(icount_label); + tcg_gen_exit_tb((long)tb + 2); + } +} + +static inline void gen_io_start(void) +{ + TCGv_i32 tmp = tcg_const_i32(1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free_i32(tmp); +} + +static inline void gen_io_end(void) +{ + TCGv_i32 tmp = tcg_const_i32(0); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); + tcg_temp_free_i32(tmp); +} diff --git a/qemu/qemu-git/host-utils.c b/qemu/qemu-git/host-utils.c new file mode 100644 index 0000000..dc96123 --- /dev/null +++ b/qemu/qemu-git/host-utils.c @@ -0,0 +1,105 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2007 Aurelien Jarno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "host-utils.h" + +//#define DEBUG_MULDIV + +/* Long integer helpers */ +#if !defined(__x86_64__) +static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; +} + +static void neg128 (uint64_t *plow, uint64_t *phigh) +{ + *plow = ~*plow; + *phigh = ~*phigh; + add128(plow, phigh, 1, 0); +} + +static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + uint32_t a0, a1, b0, b1; + uint64_t v; + + a0 = a; + a1 = a >> 32; + + b0 = b; + b1 = b >> 32; + + v = (uint64_t)a0 * (uint64_t)b0; + *plow = v; + *phigh = 0; + + v = (uint64_t)a0 * (uint64_t)b1; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b0; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b1; + *phigh += v; +} + +/* Unsigned 64x64 -> 128 multiplication */ +void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + mul64(plow, phigh, a, b); +#if defined(DEBUG_MULDIV) + printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} + +/* Signed 64x64 -> 128 multiplication */ +void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +{ + int sa, sb; + + sa = (a < 0); + if (sa) + a = -a; + sb = (b < 0); + if (sb) + b = -b; + mul64(plow, phigh, a, b); + if (sa ^ sb) { + neg128(plow, phigh); + } +#if defined(DEBUG_MULDIV) + printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} +#endif /* !defined(__x86_64__) */ diff --git a/qemu/qemu-git/host-utils.h b/qemu/qemu-git/host-utils.h new file mode 100644 index 0000000..0ddc176 --- /dev/null +++ b/qemu/qemu-git/host-utils.h @@ -0,0 +1,236 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2007 Thiemo Seufer + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "osdep.h" + +#if defined(__x86_64__) +#define __HAVE_FAST_MULU64__ +static inline void mulu64(uint64_t *plow, uint64_t *phigh, + uint64_t a, uint64_t b) +{ + __asm__ ("mul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#define __HAVE_FAST_MULS64__ +static inline void muls64(uint64_t *plow, uint64_t *phigh, + int64_t a, int64_t b) +{ + __asm__ ("imul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#else +void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); +void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); +#endif + +/* Binary search for leading zeros. */ + +static inline int clz32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clz(val); + else + return 32; +#else + int cnt = 0; + + if (!(val & 0xFFFF0000U)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF000000U)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF0000000U)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC0000000U)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x80000000U)) { + cnt++; + val <<= 1; + } + if (!(val & 0x80000000U)) { + cnt++; + } + return cnt; +#endif +} + +static inline int clo32(uint32_t val) +{ + return clz32(~val); +} + +static inline int clz64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_clzll(val); + else + return 64; +#else + int cnt = 0; + + if (!(val >> 32)) { + cnt += 32; + } else { + val >>= 32; + } + + return cnt + clz32(val); +#endif +} + +static inline int clo64(uint64_t val) +{ + return clz64(~val); +} + +static inline int ctz32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctz(val); + else + return 32; +#else + int cnt; + + cnt = 0; + if (!(val & 0x0000FFFFUL)) { + cnt += 16; + val >>= 16; + } + if (!(val & 0x000000FFUL)) { + cnt += 8; + val >>= 8; + } + if (!(val & 0x0000000FUL)) { + cnt += 4; + val >>= 4; + } + if (!(val & 0x00000003UL)) { + cnt += 2; + val >>= 2; + } + if (!(val & 0x00000001UL)) { + cnt++; + val >>= 1; + } + if (!(val & 0x00000001UL)) { + cnt++; + } + + return cnt; +#endif +} + +static inline int cto32(uint32_t val) +{ + return ctz32(~val); +} + +static inline int ctz64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + if (val) + return __builtin_ctzll(val); + else + return 64; +#else + int cnt; + + cnt = 0; + if (!((uint32_t)val)) { + cnt += 32; + val >>= 32; + } + + return cnt + ctz32(val); +#endif +} + +static inline int cto64(uint64_t val) +{ + return ctz64(~val); +} + +static inline int ctpop8(uint8_t val) +{ + val = (val & 0x55) + ((val >> 1) & 0x55); + val = (val & 0x33) + ((val >> 2) & 0x33); + val = (val & 0x0f) + ((val >> 4) & 0x0f); + + return val; +} + +static inline int ctpop16(uint16_t val) +{ + val = (val & 0x5555) + ((val >> 1) & 0x5555); + val = (val & 0x3333) + ((val >> 2) & 0x3333); + val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f); + val = (val & 0x00ff) + ((val >> 8) & 0x00ff); + + return val; +} + +static inline int ctpop32(uint32_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcount(val); +#else + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); + val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); + + return val; +#endif +} + +static inline int ctpop64(uint64_t val) +{ +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcountll(val); +#else + val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL); + val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL); + + return val; +#endif +} diff --git a/qemu/qemu-git/hostregs_helper.h b/qemu/qemu-git/hostregs_helper.h new file mode 100644 index 0000000..3a0bece --- /dev/null +++ b/qemu/qemu-git/hostregs_helper.h @@ -0,0 +1,61 @@ +/* + * Save/restore host registers. + * + * Copyright (c) 2007 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* The GCC global register variable extension is used to reserve some + host registers for use by generated code. However only the core parts of + the translation engine are compiled with these settings. We must manually + save/restore these registers when called from regular code. + It is not sufficient to save/restore T0 et. al. as these may be declared + with a datatype smaller than the actual register. */ + +#if defined(DECLARE_HOST_REGS) + +#define DO_REG(REG) \ + register host_reg_t reg_AREG##REG asm(AREG##REG); \ + volatile host_reg_t saved_AREG##REG; + +#elif defined(SAVE_HOST_REGS) + +#define DO_REG(REG) \ + __asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \ + saved_AREG##REG = reg_AREG##REG; + +#else + +#define DO_REG(REG) \ + reg_AREG##REG = saved_AREG##REG; \ + __asm__ __volatile__ ("" : : "r" (reg_AREG##REG)); + +#endif + +#ifdef AREG0 +DO_REG(0) +#endif + +#ifdef AREG1 +DO_REG(1) +#endif + +#ifdef AREG2 +DO_REG(2) +#endif + +#undef SAVE_HOST_REGS +#undef DECLARE_HOST_REGS +#undef DO_REG diff --git a/qemu/qemu-git/hppa-dis.c b/qemu/qemu-git/hppa-dis.c new file mode 100644 index 0000000..9d96d72 --- /dev/null +++ b/qemu/qemu-git/hppa-dis.c @@ -0,0 +1,2831 @@ +/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. + Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003, + 2005 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include "dis-asm.h" + +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2003 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _LIBHPPA_H +#define _LIBHPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11, + R_HPPA_LTPSEL = 0x12, + R_HPPA_RTPSEL = 0x13 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL, + e_ltpsel = R_HPPA_LTPSEL, + e_rtpsel = R_HPPA_RTPSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) \ + (((a) >> 22) & 0x3ff) +#define HPPA_R_CONSTANT(a) \ + ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22)) +#define HPPA_R_ADDEND(r, c) \ + (((r) << 22) + ((c) & 0x3fffff)) + + +/* Some functions to manipulate PA instructions. */ + +/* Declare the functions with the unused attribute to avoid warnings. */ +static inline int sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED; +static inline bfd_signed_vma hppa_field_adjust + (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) + ATTRIBUTE_UNUSED; +static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED; + + +/* The *sign_extend functions are used to assemble various bitfields + taken from an instruction and return the resulting immediate + value. */ + +static inline int +sign_extend (int x, int len) +{ + int signbit = (1 << (len - 1)); + int mask = (signbit << 1) - 1; + return ((x & mask) ^ signbit) - signbit; +} + +static inline int +low_sign_extend (int x, int len) +{ + return (x >> 1) - ((x & 1) << (len - 1)); +} + + +/* The re_assemble_* functions prepare an immediate value for + insertion into an opcode. pa-risc uses all sorts of weird bitfields + in the instruction to hold the value. */ + +static inline int +sign_unext (int x, int len) +{ + int len_ones; + + len_ones = (1 << len) - 1; + + return x & len_ones; +} + +static inline int +low_sign_unext (int x, int len) +{ + int temp; + int sign; + + sign = (x >> (len-1)) & 1; + + temp = sign_unext (x, len-1); + + return (temp << 1) | sign; +} + +static inline int +re_assemble_3 (int as3) +{ + return (( (as3 & 4) << (13-2)) + | ((as3 & 3) << (13+1))); +} + +static inline int +re_assemble_12 (int as12) +{ + return (( (as12 & 0x800) >> 11) + | ((as12 & 0x400) >> (10 - 2)) + | ((as12 & 0x3ff) << (1 + 2))); +} + +static inline int +re_assemble_14 (int as14) +{ + return (( (as14 & 0x1fff) << 1) + | ((as14 & 0x2000) >> 13)); +} + +static inline int +re_assemble_16 (int as16) +{ + int s, t; + + /* Unusual 16-bit encoding, for wide mode only. */ + t = (as16 << 1) & 0xffff; + s = (as16 & 0x8000); + return (t ^ s ^ (s >> 1)) | (s >> 15); +} + +static inline int +re_assemble_17 (int as17) +{ + return (( (as17 & 0x10000) >> 16) + | ((as17 & 0x0f800) << (16 - 11)) + | ((as17 & 0x00400) >> (10 - 2)) + | ((as17 & 0x003ff) << (1 + 2))); +} + +static inline int +re_assemble_21 (int as21) +{ + return (( (as21 & 0x100000) >> 20) + | ((as21 & 0x0ffe00) >> 8) + | ((as21 & 0x000180) << 7) + | ((as21 & 0x00007c) << 14) + | ((as21 & 0x000003) << 12)); +} + +static inline int +re_assemble_22 (int as22) +{ + return (( (as22 & 0x200000) >> 21) + | ((as22 & 0x1f0000) << (21 - 16)) + | ((as22 & 0x00f800) << (16 - 11)) + | ((as22 & 0x000400) >> (10 - 2)) + | ((as22 & 0x0003ff) << (1 + 2))); +} + + +/* Handle field selectors for PA instructions. + The L and R (and LS, RS etc.) selectors are used in pairs to form a + full 32 bit address. eg. + + LDIL L'start,%r1 ; put left part into r1 + LDW R'start(%r1),%r2 ; add r1 and right part to form address + + This function returns sign extended values in all cases. +*/ + +static inline bfd_signed_vma +hppa_field_adjust (bfd_vma sym_val, + bfd_signed_vma addend, + enum hppa_reloc_field_selector_type_alt r_field) +{ + bfd_signed_vma value; + + value = sym_val + addend; + switch (r_field) + { + case e_fsel: + /* F: No change. */ + break; + + case e_nsel: + /* N: null selector. I don't really understand what this is all + about, but HP's documentation says "this indicates that zero + bits are to be used for the displacement on the instruction. + This fixup is used to identify three-instruction sequences to + access data (for importing shared library data)." */ + value = 0; + break; + + case e_lsel: + case e_nlsel: + /* L: Select top 21 bits. */ + value = value >> 11; + break; + + case e_rsel: + /* R: Select bottom 11 bits. */ + value = value & 0x7ff; + break; + + case e_lssel: + /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ + value = value + 0x400; + value = value >> 11; + break; + + case e_rssel: + /* RS: Select bottom 11 bits for LS. + We need to return a value such that 2048 * LS'x + RS'x == x. + ie. RS'x = x - ((x + 0x400) & -0x800) + this is just a sign extension from bit 21. */ + value = ((value & 0x7ff) ^ 0x400) - 0x400; + break; + + case e_ldsel: + /* LD: Round to next multiple of 2048 then select top 21 bits. + Yes, if we are already on a multiple of 2048, we go up to the + next one. RD in this case will be -2048. */ + value = value + 0x800; + value = value >> 11; + break; + + case e_rdsel: + /* RD: Set bits 0-20 to one. */ + value = value | -0x800; + break; + + case e_lrsel: + case e_nlrsel: + /* LR: L with rounding of the addend to nearest 8k. */ + value = sym_val + ((addend + 0x1000) & -0x2000); + value = value >> 11; + break; + + case e_rrsel: + /* RR: R with rounding of the addend to nearest 8k. + We need to return a value such that 2048 * LR'x + RR'x == x + ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) + . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) + . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ + value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); + break; + + default: + abort (); + } + return value; +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) (((insn) >> 26) & 0x3f) + +enum hppa_opcode_type +{ + /* None of the opcodes in the first group generate relocs, so we + aren't too concerned about them. */ + OP_SYSOP = 0x00, + OP_MEMMNG = 0x01, + OP_ALU = 0x02, + OP_NDXMEM = 0x03, + OP_SPOP = 0x04, + OP_DIAG = 0x05, + OP_FMPYADD = 0x06, + OP_UNDEF07 = 0x07, + OP_COPRW = 0x09, + OP_COPRDW = 0x0b, + OP_COPR = 0x0c, + OP_FLOAT = 0x0e, + OP_PRDSPEC = 0x0f, + OP_UNDEF15 = 0x15, + OP_UNDEF1d = 0x1d, + OP_FMPYSUB = 0x26, + OP_FPFUSED = 0x2e, + OP_SHEXDP0 = 0x34, + OP_SHEXDP1 = 0x35, + OP_SHEXDP2 = 0x36, + OP_UNDEF37 = 0x37, + OP_SHEXDP3 = 0x3c, + OP_SHEXDP4 = 0x3d, + OP_MULTMED = 0x3e, + OP_UNDEF3f = 0x3f, + + OP_LDIL = 0x08, + OP_ADDIL = 0x0a, + + OP_LDO = 0x0d, + OP_LDB = 0x10, + OP_LDH = 0x11, + OP_LDW = 0x12, + OP_LDWM = 0x13, + OP_STB = 0x18, + OP_STH = 0x19, + OP_STW = 0x1a, + OP_STWM = 0x1b, + + OP_LDD = 0x14, + OP_STD = 0x1c, + + OP_FLDW = 0x16, + OP_LDWL = 0x17, + OP_FSTW = 0x1e, + OP_STWL = 0x1f, + + OP_COMBT = 0x20, + OP_COMIBT = 0x21, + OP_COMBF = 0x22, + OP_COMIBF = 0x23, + OP_CMPBDT = 0x27, + OP_ADDBT = 0x28, + OP_ADDIBT = 0x29, + OP_ADDBF = 0x2a, + OP_ADDIBF = 0x2b, + OP_CMPBDF = 0x2f, + OP_BVB = 0x30, + OP_BB = 0x31, + OP_MOVB = 0x32, + OP_MOVIB = 0x33, + OP_CMPIBD = 0x3b, + + OP_COMICLR = 0x24, + OP_SUBI = 0x25, + OP_ADDIT = 0x2c, + OP_ADDI = 0x2d, + + OP_BE = 0x38, + OP_BLE = 0x39, + OP_BL = 0x3a +}; + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static inline int +hppa_rebuild_insn (int insn, int value, int r_format) +{ + switch (r_format) + { + case 11: + return (insn & ~ 0x7ff) | low_sign_unext (value, 11); + + case 12: + return (insn & ~ 0x1ffd) | re_assemble_12 (value); + + + case 10: + return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8); + + case -11: + return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4); + + case 14: + return (insn & ~ 0x3fff) | re_assemble_14 (value); + + + case -10: + return (insn & ~ 0xfff1) | re_assemble_16 (value & -8); + + case -16: + return (insn & ~ 0xfff9) | re_assemble_16 (value & -4); + + case 16: + return (insn & ~ 0xffff) | re_assemble_16 (value); + + + case 17: + return (insn & ~ 0x1f1ffd) | re_assemble_17 (value); + + case 21: + return (insn & ~ 0x1fffff) | re_assemble_21 (value); + + case 22: + return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value); + + case 32: + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _LIBHPPA_H */ +/* Table of opcodes for the PA-RISC. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS/GDB 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. +If not, see . */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ + +/* There are two kinds of delay slot nullification: normal which is + * controled by the nullification bit, and conditional, which depends + * on the direction of the branch and its success or failure. + * + * NONE is unfortunately #defined in the hiux system include files. + * #undef it away. + */ +#undef NONE +struct pa_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set... */ + unsigned long int mask; /* ... in these bits. */ + char *args; + enum pa_arch arch; + char flags; +}; + +/* Enables strict matching. Opcodes with match errors are skipped + when this bit is set. */ +#define FLAG_STRICT 0x1 + +/* + All hppa opcodes are 32 bits. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character for each operand of + the instruction. Characters used as a prefix allow any second character to + be used without conflicting with the main operand characters. + + Bit positions in this description follow HP usage of lsb = 31, + "at" is lsb of field. + + In the args field, the following characters must match exactly: + + '+,() ' + + In the args field, the following characters are unused: + + ' " - / 34 6789:; ' + '@ C M [\] ' + '` e g } ' + + Here are all the characters: + + ' !"#$%&'()*+-,./0123456789:;<=>?' + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + '`abcdefghijklmnopqrstuvwxyz{|}~ ' + +Kinds of operands: + x integer register field at 15. + b integer register field at 10. + t integer register field at 31. + a integer register field at 10 and 15 (for PERMH) + 5 5 bit immediate at 15. + s 2 bit space specifier at 17. + S 3 bit space specifier at 18. + V 5 bit immediate value at 31 + i 11 bit immediate value at 31 + j 14 bit immediate value at 31 + k 21 bit immediate value at 31 + l 16 bit immediate value at 31 (wide mode only, unusual encoding). + n nullification for branch instructions + N nullification for spop and copr instructions + w 12 bit branch displacement + W 17 bit branch displacement (PC relative) + X 22 bit branch displacement (PC relative) + z 17 bit branch displacement (just a number, not an address) + +Also these: + + . 2 bit shift amount at 25 + * 4 bit shift amount at 25 + p 5 bit shift count at 26 (to support the SHD instruction) encoded as + 31-p + ~ 6 bit shift count at 20,22:26 encoded as 63-~. + P 5 bit bit position at 26 + q 6 bit bit position at 20,22:26 + T 5 bit field length at 31 (encoded as 32-T) + % 6 bit field length at 23,27:31 (variable extract/deposit) + | 6 bit field length at 19,27:31 (fixed extract/deposit) + A 13 bit immediate at 18 (to support the BREAK instruction) + ^ like b, but describes a control register + ! sar (cr11) register + D 26 bit immediate at 31 (to support the DIAG instruction) + $ 9 bit immediate at 28 (to support POPBTS) + + v 3 bit Special Function Unit identifier at 25 + O 20 bit Special Function Unit operation split between 15 bits at 20 + and 5 bits at 31 + o 15 bit Special Function Unit operation at 20 + 2 22 bit Special Function Unit operation split between 17 bits at 20 + and 5 bits at 31 + 1 15 bit Special Function Unit operation split between 10 bits at 20 + and 5 bits at 31 + 0 10 bit Special Function Unit operation split between 5 bits at 20 + and 5 bits at 31 + u 3 bit coprocessor unit identifier at 25 + F Source Floating Point Operand Format Completer encoded 2 bits at 20 + I Source Floating Point Operand Format Completer encoded 1 bits at 20 + (for 0xe format FP instructions) + G Destination Floating Point Operand Format Completer encoded 2 bits at 18 + H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' + (very similar to 'F') + + r 5 bit immediate value at 31 (for the break instruction) + (very similar to V above, except the value is unsigned instead of + low_sign_ext) + R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) + (same as r above, except the value is in a different location) + U 10 bit immediate value at 15 (for SSM, RSM on pa2.0) + Q 5 bit immediate value at 10 (a bit position specified in + the bb instruction. It's the same as r above, except the + value is in a different location) + B 5 bit immediate value at 10 (a bit position specified in + the bb instruction. Similar to Q, but 64 bit handling is + different. + Z %r1 -- implicit target of addil instruction. + L ,%r2 completer for new syntax branch + { Source format completer for fcnv + _ Destination format completer for fcnv + h cbit for fcmp + = gfx tests for ftest + d 14 bit offset for single precision FP long load/store. + # 14 bit offset for double precision FP load long/store. + J Yet another 14 bit offset for load/store with ma,mb completers. + K Yet another 14 bit offset for load/store with ma,mb completers. + y 16 bit offset for word aligned load/store (PA2.0 wide). + & 16 bit offset for dword aligned load/store (PA2.0 wide). + < 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + > 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + Y %sr0,%r31 -- implicit target of be,l instruction. + @ implicit immediate value of 0 + +Completer operands all have 'c' as the prefix: + + cx indexed load and store completer. + cX indexed load and store completer. Like cx, but emits a space + after in disassembler. + cm short load and store completer. + cM short load and store completer. Like cm, but emits a space + after in disassembler. + cq long load and store completer (like cm, but inserted into a + different location in the target instruction). + cs store bytes short completer. + cA store bytes short completer. Like cs, but emits a space + after in disassembler. + ce long load/store completer for LDW/STW with a different encoding + than the others + cc load cache control hint + cd load and clear cache control hint + cC store cache control hint + co ordered access + + cp branch link and push completer + cP branch pop completer + cl branch link completer + cg branch gate completer + + cw read/write completer for PROBE + cW wide completer for MFCTL + cL local processor completer for cache control + cZ System Control Completer (to support LPA, LHA, etc.) + + ci correction completer for DCOR + ca add completer + cy 32 bit add carry completer + cY 64 bit add carry completer + cv signed overflow trap completer + ct trap on condition completer for ADDI, SUB + cT trap on condition completer for UADDCM + cb 32 bit borrow completer for SUB + cB 64 bit borrow completer for SUB + + ch left/right half completer + cH signed/unsigned saturation completer + cS signed/unsigned completer at 21 + cz zero/sign extension completer. + c* permutation completer + +Condition operands all have '?' as the prefix: + + ?f Floating point compare conditions (encoded as 5 bits at 31) + + ?a add conditions + ?A 64 bit add conditions + ?@ add branch conditions followed by nullify + ?d non-negated add branch conditions + ?D negated add branch conditions + ?w wide mode non-negated add branch conditions + ?W wide mode negated add branch conditions + + ?s compare/subtract conditions + ?S 64 bit compare/subtract conditions + ?t non-negated compare and branch conditions + ?n 32 bit compare and branch conditions followed by nullify + ?N 64 bit compare and branch conditions followed by nullify + ?Q 64 bit compare and branch conditions for CMPIB instruction + + ?l logical conditions + ?L 64 bit logical conditions + + ?b branch on bit conditions + ?B 64 bit branch on bit conditions + + ?x shift/extract/deposit conditions + ?X 64 bit shift/extract/deposit conditions + ?y shift/extract/deposit conditions followed by nullify for conditional + branches + + ?u unit conditions + ?U 64 bit unit conditions + +Floating point registers all have 'f' as a prefix: + + ft target register at 31 + fT target register with L/R halves at 31 + fa operand 1 register at 10 + fA operand 1 register with L/R halves at 10 + fX Same as fA, except prints a space before register during disasm + fb operand 2 register at 15 + fB operand 2 register with L/R halves at 15 + fC operand 3 register with L/R halves at 16:18,21:23 + fe Like fT, but encoding is different. + fE Same as fe, except prints a space before register during disasm. + fx target register at 15 (only for PA 2.0 long format FLDD/FSTD). + +Float registers for fmpyadd and fmpysub: + + fi mult operand 1 register at 10 + fj mult operand 2 register at 15 + fk mult target register at 20 + fl add/sub operand register at 25 + fm add/sub target register at 31 + +*/ + + +#if 0 +/* List of characters not to put a space after. Note that + "," is included, as the "spopN" operations use literal + commas in their completer sections. */ +static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}"; +#endif + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic be + consecutive. If they aren't, the assembler will bomb at runtime. + + * Immediate fields use pa_get_absolute_expression to parse the + string. It will generate a "bad expression" error if passed + a register name. Thus, register index variants of an opcode + need to precede immediate variants. + + * The disassembler does not care about the order of the opcodes + except in cases where implicit addressing is used. + + Here are the rules for ordering the opcodes of a mnemonic: + + 1) Opcodes with FLAG_STRICT should precede opcodes without + FLAG_STRICT. + + 2) Opcodes with FLAG_STRICT should be ordered as follows: + register index opcodes, short immediate opcodes, and finally + long immediate opcodes. When both pa10 and pa11 variants + of the same opcode are available, the pa10 opcode should + come first for correct architectural promotion. + + 3) When implicit addressing is available for an opcode, the + implicit opcode should precede the explicit opcode. + + 4) Opcodes without FLAG_STRICT should be ordered as follows: + register index opcodes, long immediate opcodes, and finally + short immediate opcodes. */ + +static const struct pa_opcode pa_opcodes[] = +{ + +/* Pseudo-instructions. */ + +{ "ldi", 0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */ +{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */ + +{ "cmpib", 0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT}, +{ "cmpib", 0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT}, +{ "comib", 0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comib", 0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +{ "cmpb", 0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT}, +{ "cmpb", 0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT}, +{ "comb", 0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comb", 0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +{ "addb", 0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT}, +{ "addb", 0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addb", 0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0}, +{ "addib", 0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT}, +{ "addib", 0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addib", 0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +{ "nop", 0x08000240, 0xffffffff, "", pa10, 0}, /* or 0,0,0 */ +{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10, 0}, /* or r,0,t */ +{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */ + +/* Loads and Stores for integer registers. */ + +{ "ldd", 0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldh", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldb", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "std", 0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "sth", 0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "stb", 0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldwa", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwa", 0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "stwa", 0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "ldda", 0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, +{ "stdby", 0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT}, +{ "stdby", 0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0}, +{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0}, + +/* Immediate instructions. */ +{ "ldo", 0x34000000, 0xfc000000, "l(b),x", pa20w, 0}, +{ "ldo", 0x34000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldil", 0x20000000, 0xfc000000, "k,b", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b,Z", pa10, 0}, +{ "addil", 0x28000000, 0xfc000000, "k,b", pa10, 0}, + +/* Branching instructions. */ +{ "b", 0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT}, +{ "b", 0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT}, +{ "b", 0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT}, +{ "b", 0xe8000000, 0xffe0e000, "nW", pa10, 0}, /* b,l foo,r0 */ +{ "bl", 0xe8000000, 0xfc00e000, "nW,b", pa10, 0}, +{ "gate", 0xe8002000, 0xfc00e000, "nW,b", pa10, 0}, +{ "blr", 0xe8004000, 0xfc00e001, "nx,b", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0}, +{ "bv", 0xe800c000, 0xfc00fffd, "n(b)", pa10, 0}, +{ "bve", 0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT}, +{ "bve", 0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT}, +{ "bve", 0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT}, +{ "be", 0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "be", 0xe0000000, 0xfc000000, "nz(b)", pa10, 0}, +{ "ble", 0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0}, +{ "movb", 0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0}, +{ "movib", 0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0}, +{ "combt", 0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "combf", 0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0}, +{ "comibt", 0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "comibf", 0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0}, +{ "addbt", 0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addbf", 0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0}, +{ "addibt", 0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "addibf", 0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0}, +{ "bb", 0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT}, +{ "bb", 0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT}, +{ "bb", 0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT}, +{ "bvb", 0xc0004000, 0xffe04000, "?bnx,w", pa10, 0}, +{ "clrbts", 0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "popbts", 0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT}, +{ "pushnom", 0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT}, +{ "pushbts", 0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT}, + +/* Computation Instructions. */ + +{ "cmpclr", 0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT}, +{ "cmpclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT}, +{ "comclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "or", 0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "or", 0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "xor", 0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "xor", 0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "and", 0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "and", 0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "andcm", 0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, +{ "andcm", 0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0}, +{ "uxor", 0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT}, +{ "uxor", 0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcm", 0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT}, +{ "uaddcm", 0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "uaddcmt", 0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0}, +{ "dcor", 0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT}, +{ "dcor", 0x08000b80, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "idcor", 0x08000bc0, 0xfc1f0fe0, "?ub,t", pa10, 0}, +{ "addi", 0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT}, +{ "addi", 0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addio", 0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addit", 0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "addito", 0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0}, +{ "add", 0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT}, +{ "add", 0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT}, +{ "add", 0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addl", 0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addo", 0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addc", 0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "addco", 0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sub", 0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT}, +{ "sub", 0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subo", 0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subb", 0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subbo", 0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subt", 0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subto", 0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "ds", 0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0}, +{ "subi", 0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT}, +{ "subi", 0x94000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "subio", 0x94000800, 0xfc000800, "?si,b,x", pa10, 0}, +{ "cmpiclr", 0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT}, +{ "cmpiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT}, +{ "comiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, 0}, +{ "shladd", 0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT}, +{ "shladd", 0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT}, +{ "sh1add", 0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addl", 0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh1addo", 0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2add", 0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addl", 0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh2addo", 0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3add", 0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addl", 0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0}, +{ "sh3addo", 0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0}, + +/* Subword Operation Instructions. */ + +{ "hadd", 0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "havg", 0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT}, +{ "hshl", 0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT}, +{ "hshladd", 0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hshr", 0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT}, +{ "hshradd", 0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, +{ "hsub", 0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, +{ "mixh", 0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "mixw", 0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, +{ "permh", 0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT}, + + +/* Extract and Deposit Instructions. */ + +{ "shrpd", 0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT}, +{ "shrpd", 0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT}, +{ "shrpw", 0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT}, +{ "shrpw", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT}, +{ "vshd", 0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0}, +{ "shd", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0}, +{ "extrd", 0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT}, +{ "extrd", 0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT}, +{ "extrw", 0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT}, +{ "extrw", 0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT}, +{ "vextru", 0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "vextrs", 0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0}, +{ "extru", 0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "extrs", 0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0}, +{ "depd", 0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT}, +{ "depd", 0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT}, +{ "depdi", 0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT}, +{ "depdi", 0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT}, +{ "depw", 0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT}, +{ "depw", 0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT}, +{ "depwi", 0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT}, +{ "zvdep", 0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "vdep", 0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0}, +{ "zdep", 0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "dep", 0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0}, +{ "zvdepi", 0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "vdepi", 0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0}, +{ "zdepi", 0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0}, +{ "depi", 0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0}, + +/* System Control Instructions. */ + +{ "break", 0x00000000, 0xfc001fe0, "r,A", pa10, 0}, +{ "rfi", 0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT}, +{ "rfi", 0x00000c00, 0xffffffff, "", pa10, 0}, +{ "rfir", 0x00000ca0, 0xffffffff, "", pa11, 0}, +{ "ssm", 0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "ssm", 0x00000d60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "rsm", 0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, +{ "rsm", 0x00000e60, 0xffe0ffe0, "R,t", pa10, 0}, +{ "mtsm", 0x00001860, 0xffe0ffff, "x", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0}, +{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0}, +{ "mtsp", 0x00001820, 0xffe01fff, "x,S", pa10, 0}, +{ "mtctl", 0x00001840, 0xfc00ffff, "x,^", pa10, 0}, +{ "mtsarcm", 0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT}, +{ "mfia", 0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT}, +{ "mfsp", 0x000004a0, 0xffff1fe0, "S,t", pa10, 0}, +{ "mfctl", 0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT}, +{ "mfctl", 0x000008a0, 0xfc1fffe0, "^,t", pa10, 0}, +{ "sync", 0x00000400, 0xffffffff, "", pa10, 0}, +{ "syncdma", 0x00100400, 0xffffffff, "", pa10, 0}, +{ "probe", 0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT}, +{ "probe", 0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT}, +{ "probei", 0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT}, +{ "prober", 0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "prober", 0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "proberi", 0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0}, +{ "probew", 0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0}, +{ "probewi", 0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0}, +{ "lpa", 0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0}, +{ "lci", 0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0}, +{ "lci", 0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0}, +{ "pdtlb", 0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT}, +{ "pdtlb", 0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlb", 0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlb", 0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT}, +{ "pitlb", 0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdtlbe", 0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "pitlbe", 0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlba", 0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlba", 0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc00ffff, "x,(b)", pa10, 0}, +{ "idtlbp", 0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0}, +{ "iitlbp", 0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "pdc", 0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT}, +{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fic", 0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT}, +{ "fic", 0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0}, +{ "fdce", 0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0}, +{ "fice", 0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0}, +{ "diag", 0x14000000, 0xfc000000, "D", pa10, 0}, +{ "idtlbt", 0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, +{ "iitlbt", 0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, + +/* These may be specific to certain versions of the PA. Joel claimed + they were 72000 (7200?) specific. However, I'm almost certain the + mtcpu/mfcpu were undocumented, but available in the older 700 machines. */ +{ "mtcpu", 0x14001600, 0xfc00ffff, "x,^", pa10, 0}, +{ "mfcpu", 0x14001A00, 0xfc00ffff, "^,x", pa10, 0}, +{ "tocen", 0x14403600, 0xffffffff, "", pa10, 0}, +{ "tocdis", 0x14401620, 0xffffffff, "", pa10, 0}, +{ "shdwgr", 0x14402600, 0xffffffff, "", pa10, 0}, +{ "grshdw", 0x14400620, 0xffffffff, "", pa10, 0}, + +/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either + the Timex FPU or the Mustang ERS (not sure which) manual. */ +{ "gfw", 0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfw", 0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0}, +{ "gfr", 0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0}, + +/* Floating Point Coprocessor Instructions. */ + +{ "fldw", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT}, +{ "fldw", 0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT}, +{ "fldd", 0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, +{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT}, +{ "fstw", 0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstd", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT}, +{ "fstd", 0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, +{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0}, +{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, +{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, +{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0}, +{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, +{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, +{ "fstqx", 0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, +{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0}, +{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, +{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0}, +{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT}, +{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0}, +{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, +{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, +{ "fstqs", 0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, +{ "fadd", 0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fadd", 0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsub", 0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fsub", 0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fmpy", 0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fmpy", 0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fdiv", 0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "fdiv", 0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, +{ "fsqrt", 0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fsqrt", 0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fabs", 0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fabs", 0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "frem", 0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, +{ "frem", 0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0}, +{ "frnd", 0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "frnd", 0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcpy", 0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, +{ "fcpy", 0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0}, +{ "fcnvff", 0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvff", 0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvxf", 0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvxf", 0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfx", 0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfx", 0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fcnvfxt", 0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, +{ "fcnvfxt", 0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0}, +{ "fmpyfadd", 0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fmpynfadd", 0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fneg", 0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, +{ "fnegabs", 0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT}, +{ "fcnv", 0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0}, +{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0}, +{ "xmpyu", 0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0}, +{ "fmpyadd", 0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "fmpysub", 0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, +{ "ftest", 0x30002420, 0xffffffff, "", pa10, FLAG_STRICT}, +{ "ftest", 0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT}, +{ "ftest", 0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT}, +{ "fid", 0x30000000, 0xffffffff, "", pa11, 0}, + +/* Performance Monitor Instructions. */ + +{ "pmdis", 0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT}, +{ "pmenb", 0x30000680, 0xffffffff, "", pa20, FLAG_STRICT}, + +/* Assist Instructions. */ + +{ "spop0", 0x10000000, 0xfc000600, "v,ON", pa10, 0}, +{ "spop1", 0x10000200, 0xfc000600, "v,oNt", pa10, 0}, +{ "spop2", 0x10000400, 0xfc000600, "v,1Nb", pa10, 0}, +{ "spop3", 0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0}, +{ "copr", 0x30000000, 0xfc000000, "u,2N", pa10, 0}, +{ "cldw", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldw", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldd", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstw", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstd", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, +{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, +{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, +{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, +{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, +{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, +{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, + +/* More pseudo instructions which must follow the main table. */ +{ "call", 0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, +{ "call", 0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT}, +{ "ret", 0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT}, + +}; + +#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) + +/* SKV 12/18/92. Added some denotations for various operands. */ + +#define PA_IMM11_AT_31 'i' +#define PA_IMM14_AT_31 'j' +#define PA_IMM21_AT_31 'k' +#define PA_DISP12 'w' +#define PA_DISP17 'W' + +#define N_HPPA_OPERAND_FORMATS 5 + +/* Integer register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const reg_names[] = +{ + "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", + "sp", "r31" +}; + +/* Floating point register names, indexed by the numbers which appear in the + opcodes. */ +static const char *const fp_reg_names[] = +{ + "fpsr", "fpe2", "fpe4", "fpe6", + "fr4", "fr5", "fr6", "fr7", "fr8", + "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", + "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", + "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31" +}; + +typedef unsigned int CORE_ADDR; + +/* Get at various relevent fields of an instruction word. */ + +#define MASK_5 0x1f +#define MASK_10 0x3ff +#define MASK_11 0x7ff +#define MASK_14 0x3fff +#define MASK_16 0xffff +#define MASK_21 0x1fffff + +/* These macros get bit fields using HP's numbering (MSB = 0). */ + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) + +#define GET_BIT(X, WHICH) \ + GET_FIELD (X, WHICH, WHICH) + +/* Some of these have been converted to 2-d arrays because they + consume less storage this way. If the maintenance becomes a + problem, convert them back to const 1-d pointer arrays. */ +static const char *const control_reg[] = +{ + "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", + "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", + "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", + "tr4", "tr5", "tr6", "tr7" +}; + +static const char *const compare_cond_names[] = +{ + "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev" +}; +static const char *const compare_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev" +}; +static const char *const cmpib_cond_64_names[] = +{ + ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>" +}; +static const char *const add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od", + ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev" +}; +static const char *const add_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od", + ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev" +}; +static const char *const wide_add_cond_names[] = +{ + "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=", + ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>" +}; +static const char *const logical_cond_names[] = +{ + "", ",=", ",<", ",<=", 0, 0, 0, ",od", + ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; +static const char *const logical_cond_64_names[] = +{ + "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", + ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"}; +static const char *const unit_cond_names[] = +{ + "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc", + ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc" +}; +static const char *const unit_cond_64_names[] = +{ + "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc", + ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc" +}; +static const char *const shift_cond_names[] = +{ + "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" +}; +static const char *const shift_cond_64_names[] = +{ + "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" +}; +static const char *const bb_cond_64_names[] = +{ + ",*<", ",*>=" +}; +static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"}; +static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; +static const char *const short_bytes_compl_names[] = +{ + "", ",b,m", ",e", ",e,m" +}; +static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; +static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"}; +static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"}; +static const char *const float_comp_names[] = +{ + ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", + ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", + ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", + ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" +}; +static const char *const signed_unsigned_names[] = {",u", ",s"}; +static const char *const mix_half_names[] = {",l", ",r"}; +static const char *const saturation_names[] = {",us", ",ss", 0, ""}; +static const char *const read_write_names[] = {",r", ",w"}; +static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; + +/* For a bunch of different instructions form an index into a + completer name table. */ +#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ + GET_FIELD (insn, 18, 18) << 1) + +#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ + (GET_FIELD ((insn), 19, 19) ? 8 : 0)) + +/* Utility function to print registers. Put these first, so gcc's function + inlining can do its stuff. */ + +#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) + +static void +fput_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0"); +} + +static void +fput_fp_reg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_fp_reg_r (unsigned reg, disassemble_info *info) +{ + /* Special case floating point exception registers. */ + if (reg < 4) + (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); + else + (*info->fprintf_func) (info->stream, "%sR", + reg ? fp_reg_names[reg] : "fr0"); +} + +static void +fput_creg (unsigned reg, disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, control_reg[reg]); +} + +/* Print constants with sign. */ + +static void +fput_const (unsigned num, disassemble_info *info) +{ + if ((int) num < 0) + (*info->fprintf_func) (info->stream, "-%x", - (int) num); + else + (*info->fprintf_func) (info->stream, "%x", num); +} + +/* Routines to extract various sized constants out of hppa + instructions. */ + +/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ +static int +extract_3 (unsigned word) +{ + return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); +} + +static int +extract_5_load (unsigned word) +{ + return low_sign_extend (word >> 16 & MASK_5, 5); +} + +/* Extract the immediate field from a st{bhw}s instruction. */ + +static int +extract_5_store (unsigned word) +{ + return low_sign_extend (word & MASK_5, 5); +} + +/* Extract the immediate field from a break instruction. */ + +static unsigned +extract_5r_store (unsigned word) +{ + return (word & MASK_5); +} + +/* Extract the immediate field from a {sr}sm instruction. */ + +static unsigned +extract_5R_store (unsigned word) +{ + return (word >> 16 & MASK_5); +} + +/* Extract the 10 bit immediate field from a {sr}sm instruction. */ + +static unsigned +extract_10U_store (unsigned word) +{ + return (word >> 16 & MASK_10); +} + +/* Extract the immediate field from a bb instruction. */ + +static unsigned +extract_5Q_store (unsigned word) +{ + return (word >> 21 & MASK_5); +} + +/* Extract an 11 bit immediate field. */ + +static int +extract_11 (unsigned word) +{ + return low_sign_extend (word & MASK_11, 11); +} + +/* Extract a 14 bit immediate field. */ + +static int +extract_14 (unsigned word) +{ + return low_sign_extend (word & MASK_14, 14); +} + +/* Extract a 16 bit immediate field (PA2.0 wide only). */ + +static int +extract_16 (unsigned word) +{ + int m15, m0, m1; + + m0 = GET_BIT (word, 16); + m1 = GET_BIT (word, 17); + m15 = GET_BIT (word, 31); + word = (word >> 1) & 0x1fff; + word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); + return sign_extend (word, 16); +} + +/* Extract a 21 bit constant. */ + +static int +extract_21 (unsigned word) +{ + int val; + + word &= MASK_21; + word <<= 11; + val = GET_FIELD (word, 20, 20); + val <<= 11; + val |= GET_FIELD (word, 9, 19); + val <<= 2; + val |= GET_FIELD (word, 5, 6); + val <<= 5; + val |= GET_FIELD (word, 0, 4); + val <<= 2; + val |= GET_FIELD (word, 7, 8); + return sign_extend (val, 21) << 11; +} + +/* Extract a 12 bit constant from branch instructions. */ + +static int +extract_12 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | (word & 0x1) << 11, 12) << 2; +} + +/* Extract a 17 bit constant from branch instructions, returning the + 19 bit signed value. */ + +static int +extract_17 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | (word & 0x1) << 16, 17) << 2; +} + +static int +extract_22 (unsigned word) +{ + return sign_extend (GET_FIELD (word, 19, 28) + | GET_FIELD (word, 29, 29) << 10 + | GET_FIELD (word, 11, 15) << 11 + | GET_FIELD (word, 6, 10) << 16 + | (word & 0x1) << 21, 22) << 2; +} + +/* Print one instruction. */ + +int +print_insn_hppa (bfd_vma memaddr, disassemble_info *info) +{ + bfd_byte buffer[4]; + unsigned int insn, i; + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + insn = bfd_getb32 (buffer); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct pa_opcode *opcode = &pa_opcodes[i]; + + if ((insn & opcode->mask) == opcode->match) + { + const char *s; +#ifndef BFD64 + if (opcode->arch == pa20w) + continue; +#endif + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0])) + (*info->fprintf_func) (info->stream, " "); + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case 'x': + fput_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'a': + case 'b': + fput_reg (GET_FIELD (insn, 6, 10), info); + break; + case '^': + fput_creg (GET_FIELD (insn, 6, 10), info); + break; + case 't': + fput_reg (GET_FIELD (insn, 27, 31), info); + break; + + /* Handle floating point registers. */ + case 'f': + switch (*++s) + { + case 't': + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); + else + fput_fp_reg (GET_FIELD (insn, 27, 31), info); + break; + case 'a': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + + /* 'fA' will not generate a space before the regsiter + name. Normally that is fine. Except that it + causes problems with xmpyu which has no FP format + completer. */ + case 'X': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'A': + if (GET_FIELD (insn, 24, 24)) + fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); + else + fput_fp_reg (GET_FIELD (insn, 6, 10), info); + break; + case 'b': + if (GET_FIELD (insn, 25, 25)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'B': + if (GET_FIELD (insn, 19, 19)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'C': + { + int reg = GET_FIELD (insn, 21, 22); + reg |= GET_FIELD (insn, 16, 18) << 2; + if (GET_FIELD (insn, 23, 23) != 0) + fput_fp_reg_r (reg, info); + else + fput_fp_reg (reg, info); + break; + } + case 'i': + { + int reg = GET_FIELD (insn, 6, 10); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'j': + { + int reg = GET_FIELD (insn, 11, 15); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'k': + { + int reg = GET_FIELD (insn, 27, 31); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'l': + { + int reg = GET_FIELD (insn, 21, 25); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + case 'm': + { + int reg = GET_FIELD (insn, 16, 20); + + reg |= (GET_FIELD (insn, 26, 26) << 4); + fput_fp_reg (reg, info); + break; + } + + /* 'fe' will not generate a space before the register + name. Normally that is fine. Except that it + causes problems with fstw fe,y(b) which has no FP + format completer. */ + case 'E': + fputs_filtered (" ", info); + /* FALLTHRU */ + + case 'e': + if (GET_FIELD (insn, 30, 30)) + fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); + else + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + case 'x': + fput_fp_reg (GET_FIELD (insn, 11, 15), info); + break; + } + break; + + case '5': + fput_const (extract_5_load (insn), info); + break; + case 's': + { + int space = GET_FIELD (insn, 16, 17); + /* Zero means implicit addressing, not use of sr0. */ + if (space != 0) + (*info->fprintf_func) (info->stream, "sr%d", space); + } + break; + + case 'S': + (*info->fprintf_func) (info->stream, "sr%d", + extract_3 (insn)); + break; + + /* Handle completers. */ + case 'c': + switch (*++s) + { + case 'x': + (*info->fprintf_func) + (info->stream, "%s", + index_compl_names[GET_COMPL (insn)]); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + index_compl_names[GET_COMPL (insn)]); + break; + case 'm': + (*info->fprintf_func) + (info->stream, "%s", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'M': + (*info->fprintf_func) + (info->stream, "%s ", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + case 'c': + case 'C': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",bc "); + break; + case 2: + (*info->fprintf_func) (info->stream, ",sl "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'd': + switch (GET_FIELD (insn, 20, 21)) + { + case 1: + (*info->fprintf_func) (info->stream, ",co "); + break; + default: + (*info->fprintf_func) (info->stream, " "); + } + break; + case 'o': + (*info->fprintf_func) (info->stream, ",o"); + break; + case 'g': + (*info->fprintf_func) (info->stream, ",gate"); + break; + case 'p': + (*info->fprintf_func) (info->stream, ",l,push"); + break; + case 'P': + (*info->fprintf_func) (info->stream, ",pop"); + break; + case 'l': + case 'L': + (*info->fprintf_func) (info->stream, ",l"); + break; + case 'w': + (*info->fprintf_func) + (info->stream, "%s ", + read_write_names[GET_FIELD (insn, 25, 25)]); + break; + case 'W': + (*info->fprintf_func) (info->stream, ",w "); + break; + case 'r': + if (GET_FIELD (insn, 23, 26) == 5) + (*info->fprintf_func) (info->stream, ",r"); + break; + case 'Z': + if (GET_FIELD (insn, 26, 26)) + (*info->fprintf_func) (info->stream, ",m "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'i': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",i"); + break; + case 'z': + if (!GET_FIELD (insn, 21, 21)) + (*info->fprintf_func) (info->stream, ",z"); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'Y': + (*info->fprintf_func) + (info->stream, ",dc%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'y': + (*info->fprintf_func) + (info->stream, ",c%s", + add_compl_names[GET_FIELD (insn, 20, 21)]); + break; + case 'v': + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 't': + (*info->fprintf_func) (info->stream, ",tc"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'B': + (*info->fprintf_func) (info->stream, ",db"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'b': + (*info->fprintf_func) (info->stream, ",b"); + if (GET_FIELD (insn, 20, 20)) + (*info->fprintf_func) (info->stream, ",tsv"); + break; + case 'T': + if (GET_FIELD (insn, 25, 25)) + (*info->fprintf_func) (info->stream, ",tc"); + break; + case 'S': + /* EXTRD/W has a following condition. */ + if (*(s + 1) == '?') + (*info->fprintf_func) + (info->stream, "%s", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + else + (*info->fprintf_func) + (info->stream, "%s ", + signed_unsigned_names[GET_FIELD (insn, 21, 21)]); + break; + case 'h': + (*info->fprintf_func) + (info->stream, "%s", + mix_half_names[GET_FIELD (insn, 17, 17)]); + break; + case 'H': + (*info->fprintf_func) + (info->stream, "%s ", + saturation_names[GET_FIELD (insn, 24, 25)]); + break; + case '*': + (*info->fprintf_func) + (info->stream, ",%d%d%d%d ", + GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21), + GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25)); + break; + + case 'q': + { + int m, a; + + m = GET_FIELD (insn, 28, 28); + a = GET_FIELD (insn, 29, 29); + + if (m && !a) + fputs_filtered (",ma ", info); + else if (m && a) + fputs_filtered (",mb ", info); + else + fputs_filtered (" ", info); + break; + } + + case 'J': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x16 || opc == 0x1e) + { + if (GET_FIELD (insn, 29, 29) == 0) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + break; + } + + case 'e': + { + int opc = GET_FIELD (insn, 0, 5); + + if (opc == 0x13 || opc == 0x1b) + { + if (GET_FIELD (insn, 18, 18) == 1) + fputs_filtered (",mb ", info); + else + fputs_filtered (",ma ", info); + } + else if (opc == 0x17 || opc == 0x1f) + { + if (GET_FIELD (insn, 31, 31) == 1) + fputs_filtered (",ma ", info); + else + fputs_filtered (",mb ", info); + } + else + fputs_filtered (" ", info); + + break; + } + } + break; + + /* Handle conditions. */ + case '?': + { + s++; + switch (*s) + { + case 'f': + (*info->fprintf_func) + (info->stream, "%s ", + float_comp_names[GET_FIELD (insn, 27, 31)]); + break; + + /* These four conditions are for the set of instructions + which distinguish true/false conditions by opcode + rather than by the 'f' bit (sigh): comb, comib, + addb, addib. */ + case 't': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18)], info); + break; + case 'n': + fputs_filtered + (compare_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 'N': + fputs_filtered + (compare_cond_64_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 2, 2) * 8], + info); + break; + case 'Q': + fputs_filtered + (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)], + info); + break; + case '@': + fputs_filtered + (add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8], + info); + break; + case 's': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_names[GET_COND (insn)]); + break; + case 'S': + (*info->fprintf_func) + (info->stream, "%s ", + compare_cond_64_names[GET_COND (insn)]); + break; + case 'a': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_names[GET_COND (insn)]); + break; + case 'A': + (*info->fprintf_func) + (info->stream, "%s ", + add_cond_64_names[GET_COND (insn)]); + break; + case 'd': + (*info->fprintf_func) + (info->stream, "%s", + add_cond_names[GET_FIELD (insn, 16, 18)]); + break; + + case 'W': + (*info->fprintf_func) + (info->stream, "%s", + wide_add_cond_names[GET_FIELD (insn, 16, 18) + + GET_FIELD (insn, 4, 4) * 8]); + break; + + case 'l': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_names[GET_COND (insn)]); + break; + case 'L': + (*info->fprintf_func) + (info->stream, "%s ", + logical_cond_64_names[GET_COND (insn)]); + break; + case 'u': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_names[GET_COND (insn)]); + break; + case 'U': + (*info->fprintf_func) + (info->stream, "%s ", + unit_cond_64_names[GET_COND (insn)]); + break; + case 'y': + case 'x': + case 'b': + (*info->fprintf_func) + (info->stream, "%s", + shift_cond_names[GET_FIELD (insn, 16, 18)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + case 'X': + (*info->fprintf_func) + (info->stream, "%s ", + shift_cond_64_names[GET_FIELD (insn, 16, 18)]); + break; + case 'B': + (*info->fprintf_func) + (info->stream, "%s", + bb_cond_64_names[GET_FIELD (insn, 16, 16)]); + + /* If the next character in args is 'n', it will handle + putting out the space. */ + if (s[1] != 'n') + (*info->fprintf_func) (info->stream, " "); + break; + } + break; + } + + case 'V': + fput_const (extract_5_store (insn), info); + break; + case 'r': + fput_const (extract_5r_store (insn), info); + break; + case 'R': + fput_const (extract_5R_store (insn), info); + break; + case 'U': + fput_const (extract_10U_store (insn), info); + break; + case 'B': + case 'Q': + fput_const (extract_5Q_store (insn), info); + break; + case 'i': + fput_const (extract_11 (insn), info); + break; + case 'j': + fput_const (extract_14 (insn), info); + break; + case 'k': + fputs_filtered ("L%", info); + fput_const (extract_21 (insn), info); + break; + case '<': + case 'l': + /* 16-bit long disp., PA2.0 wide only. */ + fput_const (extract_16 (insn), info); + break; + case 'n': + if (insn & 0x2) + (*info->fprintf_func) (info->stream, ",n "); + else + (*info->fprintf_func) (info->stream, " "); + break; + case 'N': + if ((insn & 0x20) && s[1]) + (*info->fprintf_func) (info->stream, ",n "); + else if (insn & 0x20) + (*info->fprintf_func) (info->stream, ",n"); + else if (s[1]) + (*info->fprintf_func) (info->stream, " "); + break; + case 'w': + (*info->print_address_func) + (memaddr + 8 + extract_12 (insn), info); + break; + case 'W': + /* 17 bit PC-relative branch. */ + (*info->print_address_func) + ((memaddr + 8 + extract_17 (insn)), info); + break; + case 'z': + /* 17 bit displacement. This is an offset from a register + so it gets disasssembled as just a number, not any sort + of address. */ + fput_const (extract_17 (insn), info); + break; + + case 'Z': + /* addil %r1 implicit output. */ + fputs_filtered ("r1", info); + break; + + case 'Y': + /* be,l %sr0,%r31 implicit output. */ + fputs_filtered ("sr0,r31", info); + break; + + case '@': + (*info->fprintf_func) (info->stream, "0"); + break; + + case '.': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 24, 25)); + break; + case '*': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 25)); + break; + case '!': + fputs_filtered ("sar", info); + break; + case 'p': + (*info->fprintf_func) (info->stream, "%d", + 31 - GET_FIELD (insn, 22, 26)); + break; + case '~': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", 63 - num); + break; + } + case 'P': + (*info->fprintf_func) (info->stream, "%d", + GET_FIELD (insn, 22, 26)); + break; + case 'q': + { + int num; + num = GET_FIELD (insn, 20, 20) << 5; + num |= GET_FIELD (insn, 22, 26); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case 'T': + (*info->fprintf_func) (info->stream, "%d", + 32 - GET_FIELD (insn, 27, 31)); + break; + case '%': + { + int num; + num = (GET_FIELD (insn, 23, 23) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '|': + { + int num; + num = (GET_FIELD (insn, 19, 19) + 1) * 32; + num -= GET_FIELD (insn, 27, 31); + (*info->fprintf_func) (info->stream, "%d", num); + break; + } + case '$': + fput_const (GET_FIELD (insn, 20, 28), info); + break; + case 'A': + fput_const (GET_FIELD (insn, 6, 18), info); + break; + case 'D': + fput_const (GET_FIELD (insn, 6, 31), info); + break; + case 'v': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'O': + fput_const ((GET_FIELD (insn, 6,20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'o': + fput_const (GET_FIELD (insn, 6, 20), info); + break; + case '2': + fput_const ((GET_FIELD (insn, 6, 22) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '1': + fput_const ((GET_FIELD (insn, 11, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case '0': + fput_const ((GET_FIELD (insn, 16, 20) << 5 | + GET_FIELD (insn, 27, 31)), info); + break; + case 'u': + (*info->fprintf_func) (info->stream, ",%d", + GET_FIELD (insn, 23, 25)); + break; + case 'F': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == 'G' || s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 19, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 19, 20)]); + break; + case 'G': + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 17, 18)]); + break; + case 'H': + if (GET_FIELD (insn, 26, 26) == 1) + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[0]); + else + (*info->fprintf_func) (info->stream, "%s ", + float_format_names[1]); + break; + case 'I': + /* If no destination completer and not before a completer + for fcmp, need a space here. */ + if (s[1] == '?') + fputs_filtered + (float_format_names[GET_FIELD (insn, 20, 20)], info); + else + (*info->fprintf_func) + (info->stream, "%s ", + float_format_names[GET_FIELD (insn, 20, 20)]); + break; + + case 'J': + fput_const (extract_14 (insn), info); + break; + + case '#': + { + int sign = GET_FIELD (insn, 31, 31); + int imm10 = GET_FIELD (insn, 18, 27); + int disp; + + if (sign) + disp = (-1 << 10) | imm10; + else + disp = imm10; + + disp <<= 3; + fput_const (disp, info); + break; + } + case 'K': + case 'd': + { + int sign = GET_FIELD (insn, 31, 31); + int imm11 = GET_FIELD (insn, 18, 28); + int disp; + + if (sign) + disp = (-1 << 11) | imm11; + else + disp = imm11; + + disp <<= 2; + fput_const (disp, info); + break; + } + + case '>': + case 'y': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~3; + fput_const (disp, info); + break; + } + + case '&': + { + /* 16-bit long disp., PA2.0 wide only. */ + int disp = extract_16 (insn); + disp &= ~7; + fput_const (disp, info); + break; + } + + case '_': + break; /* Dealt with by '{' */ + + case '{': + { + int sub = GET_FIELD (insn, 14, 16); + int df = GET_FIELD (insn, 17, 18); + int sf = GET_FIELD (insn, 19, 20); + const char * const * source = float_format_names; + const char * const * dest = float_format_names; + char *t = ""; + + if (sub == 4) + { + fputs_filtered (",UND ", info); + break; + } + if ((sub & 3) == 3) + t = ",t"; + if ((sub & 3) == 1) + source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + if (sub & 2) + dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; + + (*info->fprintf_func) (info->stream, "%s%s%s ", + t, source[sf], dest[df]); + break; + } + + case 'm': + { + int y = GET_FIELD (insn, 16, 18); + + if (y != 1) + fput_const ((y ^ 1) - 1, info); + } + break; + + case 'h': + { + int cbit; + + cbit = GET_FIELD (insn, 16, 18); + + if (cbit > 0) + (*info->fprintf_func) (info->stream, ",%d", cbit - 1); + break; + } + + case '=': + { + int cond = GET_FIELD (insn, 27, 31); + + switch (cond) + { + case 0: fputs_filtered (" ", info); break; + case 1: fputs_filtered ("acc ", info); break; + case 2: fputs_filtered ("rej ", info); break; + case 5: fputs_filtered ("acc8 ", info); break; + case 6: fputs_filtered ("rej8 ", info); break; + case 9: fputs_filtered ("acc6 ", info); break; + case 13: fputs_filtered ("acc4 ", info); break; + case 17: fputs_filtered ("acc2 ", info); break; + default: break; + } + break; + } + + case 'X': + (*info->print_address_func) + (memaddr + 8 + extract_22 (insn), info); + break; + case 'L': + fputs_filtered (",rp", info); + break; + default: + (*info->fprintf_func) (info->stream, "%c", *s); + break; + } + } + return sizeof (insn); + } + } + (*info->fprintf_func) (info->stream, "#%8x", insn); + return sizeof (insn); +} diff --git a/qemu/qemu-git/hppa.ld b/qemu/qemu-git/hppa.ld new file mode 100644 index 0000000..9a4b22c --- /dev/null +++ b/qemu/qemu-git/hppa.ld @@ -0,0 +1,213 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux", + "elf32-hppa-linux") +OUTPUT_ARCH(hppa:hppa1.1) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x08000240 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x08000240 + .fini : + { + KEEP (*(.fini)) + } =0x08000240 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .PARISC.unwind : { *(.PARISC.unwind) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .data : + { + PROVIDE ($global$ = .); + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/i386-dis.c b/qemu/qemu-git/i386-dis.c new file mode 100644 index 0000000..b2af033 --- /dev/null +++ b/qemu/qemu-git/i386-dis.c @@ -0,0 +1,6559 @@ +/* opcodes/i386-dis.c r1.126 */ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + July 1988 + modified by John Hassey (hassey@dg-rtp.dg.com) + x86-64 support added by Jan Hubicka (jh@suse.cz) + VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ + +/* The main tables describing the instructions is essentially a copy + of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + Programmers Manual. Usually, there is a capital letter, followed + by a small letter. The capital letter tell the addressing mode, + and the small letter tells about the operand size. Refer to + the Intel manual for details. */ + +#include +#include "dis-asm.h" +/* include/opcode/i386.h r1.78 */ + +/* opcode/i386.h -- Intel 80386 opcode macros + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived + ix86 Unix assemblers, generate floating point instructions with + reversed source and destination registers in certain cases. + Unfortunately, gcc and possibly many other programs use this + reversed syntax, so we're stuck with it. + + eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but + `fsub %st,%st(3)' results in st(3) = st - st(3), rather than + the expected st(3) = st(3) - st + + This happens with all the non-commutative arithmetic floating point + operations with two register operands, where the source register is + %st, and destination register is %st(i). + + The affected opcode map is dceX, dcfX, deeX, defX. */ + +#ifndef SYSV386_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes at your peril. gcc generates SystemV/386 + compatible instructions. */ +#define SYSV386_COMPAT 1 +#endif +#ifndef OLDGCC_COMPAT +/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could + generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands + reversed. */ +#define OLDGCC_COMPAT SYSV386_COMPAT +#endif + +#define MOV_AX_DISP32 0xa0 +#define POP_SEG_SHORT 0x07 +#define JUMP_PC_RELATIVE 0xeb +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +/* The opcode for the fwait instruction, which disassembler treats as a + prefix when it can. */ +#define FWAIT_OPCODE 0x9b +#define ADDR_PREFIX_OPCODE 0x67 +#define DATA_PREFIX_OPCODE 0x66 +#define LOCK_PREFIX_OPCODE 0xf0 +#define CS_PREFIX_OPCODE 0x2e +#define DS_PREFIX_OPCODE 0x3e +#define ES_PREFIX_OPCODE 0x26 +#define FS_PREFIX_OPCODE 0x64 +#define GS_PREFIX_OPCODE 0x65 +#define SS_PREFIX_OPCODE 0x36 +#define REPNE_PREFIX_OPCODE 0xf2 +#define REPE_PREFIX_OPCODE 0xf3 + +#define TWO_BYTE_OPCODE_ESCAPE 0x0f +#define NOP_OPCODE (char) 0x90 + +/* register numbers */ +#define EBP_REG_NUM 5 +#define ESP_REG_NUM 4 + +/* modrm_byte.regmem for twobyte escape */ +#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM +/* index_base_byte.index for no index register addressing */ +#define NO_INDEX_REGISTER ESP_REG_NUM +/* index_base_byte.base for no base register addressing */ +#define NO_BASE_REGISTER EBP_REG_NUM +#define NO_BASE_REGISTER_16 6 + +/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ +#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ +#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) + +/* x86-64 extension prefix. */ +#define REX_OPCODE 0x40 + +/* Indicates 64 bit operand size. */ +#define REX_W 8 +/* High extension to reg field of modrm byte. */ +#define REX_R 4 +/* High extension to SIB index field. */ +#define REX_X 2 +/* High extension to base field of modrm or SIB, or reg field of opcode. */ +#define REX_B 1 + +/* max operands per insn */ +#define MAX_OPERANDS 4 + +/* max immediates per insn (lcall, ljmp, insertq, extrq) */ +#define MAX_IMMEDIATE_OPERANDS 2 + +/* max memory refs per insn (string ops) */ +#define MAX_MEMORY_OPERANDS 2 + +/* max size of insn mnemonics. */ +#define MAX_MNEM_SIZE 16 + +/* max size of register name in insn mnemonics. */ +#define MAX_REG_NAME_SIZE 8 + +/* opcodes/i386-dis.c r1.126 */ +#include "qemu-common.h" + +#include + +static int fetch_data (struct disassemble_info *, bfd_byte *); +static void ckprefix (void); +static const char *prefix_name (int, int); +static int print_insn (bfd_vma, disassemble_info *); +static void dofloat (int); +static void OP_ST (int, int); +static void OP_STi (int, int); +static int putop (const char *, int); +static void oappend (const char *); +static void append_seg (void); +static void OP_indirE (int, int); +static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp); +static void print_displacement (char *, bfd_vma); +static void OP_E (int, int); +static void OP_G (int, int); +static bfd_vma get64 (void); +static bfd_signed_vma get32 (void); +static bfd_signed_vma get32s (void); +static int get16 (void); +static void set_op (bfd_vma, int); +static void OP_REG (int, int); +static void OP_IMREG (int, int); +static void OP_I (int, int); +static void OP_I64 (int, int); +static void OP_sI (int, int); +static void OP_J (int, int); +static void OP_SEG (int, int); +static void OP_DIR (int, int); +static void OP_OFF (int, int); +static void OP_OFF64 (int, int); +static void ptr_reg (int, int); +static void OP_ESreg (int, int); +static void OP_DSreg (int, int); +static void OP_C (int, int); +static void OP_D (int, int); +static void OP_T (int, int); +static void OP_R (int, int); +static void OP_MMX (int, int); +static void OP_XMM (int, int); +static void OP_EM (int, int); +static void OP_EX (int, int); +static void OP_EMC (int,int); +static void OP_MXC (int,int); +static void OP_MS (int, int); +static void OP_XS (int, int); +static void OP_M (int, int); +static void OP_VMX (int, int); +static void OP_0fae (int, int); +static void OP_0f07 (int, int); +static void NOP_Fixup1 (int, int); +static void NOP_Fixup2 (int, int); +static void OP_3DNowSuffix (int, int); +static void OP_SIMD_Suffix (int, int); +static void SIMD_Fixup (int, int); +static void PNI_Fixup (int, int); +static void SVME_Fixup (int, int); +static void INVLPG_Fixup (int, int); +static void BadOp (void); +static void VMX_Fixup (int, int); +static void REP_Fixup (int, int); +static void CMPXCHG8B_Fixup (int, int); +static void XMM_Fixup (int, int); +static void CRC32_Fixup (int, int); + +struct dis_private { + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAX_MNEM_SIZE]; + bfd_vma insn_start; + int orig_sizeflag; + jmp_buf bailout; +}; + +enum address_mode +{ + mode_16bit, + mode_32bit, + mode_64bit +}; + +static enum address_mode address_mode; + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* REX prefix the current instruction. See below. */ +static int rex; +/* Bits of REX we've already used. */ +static int rex_used; +/* Mark parts used in the REX prefix. When we are testing for + empty prefix (for 8bit register REX extension), just mask it + out. Otherwise test for REX bit is excuse for existence of REX + only in case value is nonzero. */ +#define USED_REX(value) \ + { \ + if (value) \ + { \ + if ((rex & value)) \ + rex_used |= (value) | REX_OPCODE; \ + } \ + else \ + rex_used |= REX_OPCODE; \ + } + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct dis_private *priv = (struct dis_private *) info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + if (addr <= priv->the_buffer + MAX_MNEM_SIZE) + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + else + status = -1; + if (status != 0) + { + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define XX { NULL, 0 } + +#define Eb { OP_E, b_mode } +#define Ev { OP_E, v_mode } +#define Ed { OP_E, d_mode } +#define Edq { OP_E, dq_mode } +#define Edqw { OP_E, dqw_mode } +#define Edqb { OP_E, dqb_mode } +#define Edqd { OP_E, dqd_mode } +#define indirEv { OP_indirE, stack_v_mode } +#define indirEp { OP_indirE, f_mode } +#define stackEv { OP_E, stack_v_mode } +#define Em { OP_E, m_mode } +#define Ew { OP_E, w_mode } +#define M { OP_M, 0 } /* lea, lgdt, etc. */ +#define Ma { OP_M, v_mode } +#define Mp { OP_M, f_mode } /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Mq { OP_M, q_mode } +#define Gb { OP_G, b_mode } +#define Gv { OP_G, v_mode } +#define Gd { OP_G, d_mode } +#define Gdq { OP_G, dq_mode } +#define Gm { OP_G, m_mode } +#define Gw { OP_G, w_mode } +#define Rd { OP_R, d_mode } +#define Rm { OP_R, m_mode } +#define Ib { OP_I, b_mode } +#define sIb { OP_sI, b_mode } /* sign extened byte */ +#define Iv { OP_I, v_mode } +#define Iq { OP_I, q_mode } +#define Iv64 { OP_I64, v_mode } +#define Iw { OP_I, w_mode } +#define I1 { OP_I, const_1_mode } +#define Jb { OP_J, b_mode } +#define Jv { OP_J, v_mode } +#define Cm { OP_C, m_mode } +#define Dm { OP_D, m_mode } +#define Td { OP_T, d_mode } + +#define RMeAX { OP_REG, eAX_reg } +#define RMeBX { OP_REG, eBX_reg } +#define RMeCX { OP_REG, eCX_reg } +#define RMeDX { OP_REG, eDX_reg } +#define RMeSP { OP_REG, eSP_reg } +#define RMeBP { OP_REG, eBP_reg } +#define RMeSI { OP_REG, eSI_reg } +#define RMeDI { OP_REG, eDI_reg } +#define RMrAX { OP_REG, rAX_reg } +#define RMrBX { OP_REG, rBX_reg } +#define RMrCX { OP_REG, rCX_reg } +#define RMrDX { OP_REG, rDX_reg } +#define RMrSP { OP_REG, rSP_reg } +#define RMrBP { OP_REG, rBP_reg } +#define RMrSI { OP_REG, rSI_reg } +#define RMrDI { OP_REG, rDI_reg } +#define RMAL { OP_REG, al_reg } +#define RMAL { OP_REG, al_reg } +#define RMCL { OP_REG, cl_reg } +#define RMDL { OP_REG, dl_reg } +#define RMBL { OP_REG, bl_reg } +#define RMAH { OP_REG, ah_reg } +#define RMCH { OP_REG, ch_reg } +#define RMDH { OP_REG, dh_reg } +#define RMBH { OP_REG, bh_reg } +#define RMAX { OP_REG, ax_reg } +#define RMDX { OP_REG, dx_reg } + +#define eAX { OP_IMREG, eAX_reg } +#define eBX { OP_IMREG, eBX_reg } +#define eCX { OP_IMREG, eCX_reg } +#define eDX { OP_IMREG, eDX_reg } +#define eSP { OP_IMREG, eSP_reg } +#define eBP { OP_IMREG, eBP_reg } +#define eSI { OP_IMREG, eSI_reg } +#define eDI { OP_IMREG, eDI_reg } +#define AL { OP_IMREG, al_reg } +#define CL { OP_IMREG, cl_reg } +#define DL { OP_IMREG, dl_reg } +#define BL { OP_IMREG, bl_reg } +#define AH { OP_IMREG, ah_reg } +#define CH { OP_IMREG, ch_reg } +#define DH { OP_IMREG, dh_reg } +#define BH { OP_IMREG, bh_reg } +#define AX { OP_IMREG, ax_reg } +#define DX { OP_IMREG, dx_reg } +#define zAX { OP_IMREG, z_mode_ax_reg } +#define indirDX { OP_IMREG, indir_dx_reg } + +#define Sw { OP_SEG, w_mode } +#define Sv { OP_SEG, v_mode } +#define Ap { OP_DIR, 0 } +#define Ob { OP_OFF64, b_mode } +#define Ov { OP_OFF64, v_mode } +#define Xb { OP_DSreg, eSI_reg } +#define Xv { OP_DSreg, eSI_reg } +#define Xz { OP_DSreg, eSI_reg } +#define Yb { OP_ESreg, eDI_reg } +#define Yv { OP_ESreg, eDI_reg } +#define DSBX { OP_DSreg, eBX_reg } + +#define es { OP_REG, es_reg } +#define ss { OP_REG, ss_reg } +#define cs { OP_REG, cs_reg } +#define ds { OP_REG, ds_reg } +#define fs { OP_REG, fs_reg } +#define gs { OP_REG, gs_reg } + +#define MX { OP_MMX, 0 } +#define XM { OP_XMM, 0 } +#define EM { OP_EM, v_mode } +#define EMd { OP_EM, d_mode } +#define EMq { OP_EM, q_mode } +#define EXd { OP_EX, d_mode } +#define EXq { OP_EX, q_mode } +#define EXx { OP_EX, x_mode } +#define MS { OP_MS, v_mode } +#define XS { OP_XS, v_mode } +#define EMC { OP_EMC, v_mode } +#define MXC { OP_MXC, 0 } +#define VM { OP_VMX, q_mode } +#define OPSUF { OP_3DNowSuffix, 0 } +#define OPSIMD { OP_SIMD_Suffix, 0 } +#define XMM0 { XMM_Fixup, 0 } + +/* Used handle "rep" prefix for string instructions. */ +#define Xbr { REP_Fixup, eSI_reg } +#define Xvr { REP_Fixup, eSI_reg } +#define Ybr { REP_Fixup, eDI_reg } +#define Yvr { REP_Fixup, eDI_reg } +#define Yzr { REP_Fixup, eDI_reg } +#define indirDXr { REP_Fixup, indir_dx_reg } +#define ALr { REP_Fixup, al_reg } +#define eAXr { REP_Fixup, eAX_reg } + +#define cond_jump_flag { NULL, cond_jump_mode } +#define loop_jcxz_flag { NULL, loop_jcxz_mode } + +/* bits in sizeflag */ +#define SUFFIX_ALWAYS 4 +#define AFLAG 2 +#define DFLAG 1 + +#define b_mode 1 /* byte operand */ +#define v_mode 2 /* operand size depends on prefixes */ +#define w_mode 3 /* word operand */ +#define d_mode 4 /* double word operand */ +#define q_mode 5 /* quad word operand */ +#define t_mode 6 /* ten-byte operand */ +#define x_mode 7 /* 16-byte XMM operand */ +#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ +#define cond_jump_mode 9 +#define loop_jcxz_mode 10 +#define dq_mode 11 /* operand size depends on REX prefixes. */ +#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ +#define f_mode 13 /* 4- or 6-byte pointer operand */ +#define const_1_mode 14 +#define stack_v_mode 15 /* v_mode for stack-related opcodes. */ +#define z_mode 16 /* non-quad operand size depends on prefixes */ +#define o_mode 17 /* 16-byte operand */ +#define dqb_mode 18 /* registers like dq_mode, memory like b_mode. */ +#define dqd_mode 19 /* registers like dq_mode, memory like d_mode. */ + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 + +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define rAX_reg 132 +#define rCX_reg 133 +#define rDX_reg 134 +#define rBX_reg 135 +#define rSP_reg 136 +#define rBP_reg 137 +#define rSI_reg 138 +#define rDI_reg 139 + +#define z_mode_ax_reg 149 +#define indir_dx_reg 150 + +#define FLOATCODE 1 +#define USE_GROUPS 2 +#define USE_PREFIX_USER_TABLE 3 +#define X86_64_SPECIAL 4 +#define IS_3BYTE_OPCODE 5 + +#define FLOAT NULL, { { NULL, FLOATCODE } } + +#define GRP1a NULL, { { NULL, USE_GROUPS }, { NULL, 0 } } +#define GRP1b NULL, { { NULL, USE_GROUPS }, { NULL, 1 } } +#define GRP1S NULL, { { NULL, USE_GROUPS }, { NULL, 2 } } +#define GRP1Ss NULL, { { NULL, USE_GROUPS }, { NULL, 3 } } +#define GRP2b NULL, { { NULL, USE_GROUPS }, { NULL, 4 } } +#define GRP2S NULL, { { NULL, USE_GROUPS }, { NULL, 5 } } +#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL, 6 } } +#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL, 7 } } +#define GRP2b_cl NULL, { { NULL, USE_GROUPS }, { NULL, 8 } } +#define GRP2S_cl NULL, { { NULL, USE_GROUPS }, { NULL, 9 } } +#define GRP3b NULL, { { NULL, USE_GROUPS }, { NULL, 10 } } +#define GRP3S NULL, { { NULL, USE_GROUPS }, { NULL, 11 } } +#define GRP4 NULL, { { NULL, USE_GROUPS }, { NULL, 12 } } +#define GRP5 NULL, { { NULL, USE_GROUPS }, { NULL, 13 } } +#define GRP6 NULL, { { NULL, USE_GROUPS }, { NULL, 14 } } +#define GRP7 NULL, { { NULL, USE_GROUPS }, { NULL, 15 } } +#define GRP8 NULL, { { NULL, USE_GROUPS }, { NULL, 16 } } +#define GRP9 NULL, { { NULL, USE_GROUPS }, { NULL, 17 } } +#define GRP11_C6 NULL, { { NULL, USE_GROUPS }, { NULL, 18 } } +#define GRP11_C7 NULL, { { NULL, USE_GROUPS }, { NULL, 19 } } +#define GRP12 NULL, { { NULL, USE_GROUPS }, { NULL, 20 } } +#define GRP13 NULL, { { NULL, USE_GROUPS }, { NULL, 21 } } +#define GRP14 NULL, { { NULL, USE_GROUPS }, { NULL, 22 } } +#define GRP15 NULL, { { NULL, USE_GROUPS }, { NULL, 23 } } +#define GRP16 NULL, { { NULL, USE_GROUPS }, { NULL, 24 } } +#define GRPAMD NULL, { { NULL, USE_GROUPS }, { NULL, 25 } } +#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } } +#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } } + +#define PREGRP0 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 0 } } +#define PREGRP1 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 1 } } +#define PREGRP2 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 2 } } +#define PREGRP3 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 3 } } +#define PREGRP4 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 4 } } +#define PREGRP5 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 5 } } +#define PREGRP6 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 6 } } +#define PREGRP7 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 7 } } +#define PREGRP8 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 8 } } +#define PREGRP9 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 9 } } +#define PREGRP10 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } } +#define PREGRP11 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } } +#define PREGRP12 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } } +#define PREGRP13 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } } +#define PREGRP14 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } } +#define PREGRP15 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } } +#define PREGRP16 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } } +#define PREGRP17 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } } +#define PREGRP18 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } } +#define PREGRP19 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } } +#define PREGRP20 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } } +#define PREGRP21 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } } +#define PREGRP22 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } } +#define PREGRP23 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } } +#define PREGRP24 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } } +#define PREGRP25 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } } +#define PREGRP26 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } } +#define PREGRP27 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } } +#define PREGRP28 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } } +#define PREGRP29 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } } +#define PREGRP30 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } } +#define PREGRP31 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } } +#define PREGRP32 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } } +#define PREGRP33 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } } +#define PREGRP34 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } } +#define PREGRP35 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } } +#define PREGRP36 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } } +#define PREGRP37 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } } +#define PREGRP38 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } } +#define PREGRP39 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } } +#define PREGRP40 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } } +#define PREGRP41 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } } +#define PREGRP42 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } } +#define PREGRP43 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } } +#define PREGRP44 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } } +#define PREGRP45 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } } +#define PREGRP46 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } } +#define PREGRP47 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } } +#define PREGRP48 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } } +#define PREGRP49 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } } +#define PREGRP50 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } } +#define PREGRP51 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } } +#define PREGRP52 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } } +#define PREGRP53 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } } +#define PREGRP54 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } } +#define PREGRP55 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } } +#define PREGRP56 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } } +#define PREGRP57 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } } +#define PREGRP58 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } } +#define PREGRP59 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } } +#define PREGRP60 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } } +#define PREGRP61 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } } +#define PREGRP62 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } } +#define PREGRP63 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } } +#define PREGRP64 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } } +#define PREGRP65 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } } +#define PREGRP66 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } } +#define PREGRP67 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } } +#define PREGRP68 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } } +#define PREGRP69 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } } +#define PREGRP70 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } } +#define PREGRP71 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } } +#define PREGRP72 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } } +#define PREGRP73 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } } +#define PREGRP74 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } } +#define PREGRP75 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } } +#define PREGRP76 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } } +#define PREGRP77 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } } +#define PREGRP78 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } } +#define PREGRP79 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } } +#define PREGRP80 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } } +#define PREGRP81 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } } +#define PREGRP82 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } } +#define PREGRP83 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } } +#define PREGRP84 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } } +#define PREGRP85 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } } +#define PREGRP86 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } } +#define PREGRP87 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } } +#define PREGRP88 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } } +#define PREGRP89 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } } +#define PREGRP90 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } } +#define PREGRP91 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } } +#define PREGRP92 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } } +#define PREGRP93 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } } +#define PREGRP94 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } } +#define PREGRP95 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } } +#define PREGRP96 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } } +#define PREGRP97 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } } + + +#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } } +#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } } +#define X86_64_2 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } } +#define X86_64_3 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } } + +#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } } +#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } } + +typedef void (*op_rtn) (int bytemode, int sizeflag); + +struct dis386 { + const char *name; + struct + { + op_rtn rtn; + int bytemode; + } op[MAX_OPERANDS]; +}; + +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand + . size prefix + 'D' => print 'w' if no register operands or 'w', 'l' or 'q', if + . suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'F' => print 'w' or 'l' depending on address size prefix (loop insns) + 'G' => print 'w' or 'l' depending on operand size prefix (i/o insns) + 'H' => print ",pt" or ",pn" branch hint + 'I' => honor following macro letter even in Intel mode (implemented only + . for some of the macro letters) + 'J' => print 'l' + 'K' => print 'd' or 'q' if rex prefix is present. + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'O' => print 'd' or 'o' (or 'q' in Intel mode) + 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true + 'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode) + 'S' => print 'w', 'l' or 'q' if suffix_always is true + 'T' => print 'q' in 64bit mode and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise + 'V' => print 'q' in 64bit mode and behave as 'S' otherwise + 'W' => print 'b', 'w' or 'l' ('d' in Intel mode) + 'X' => print 's', 'd' depending on data16 prefix (for XMM) + 'Y' => 'q' if instruction has an REX 64bit overwrite prefix + 'Z' => print 'q' in 64bit mode and behave as 'L' otherwise + + Many of the above letters print nothing in Intel mode. See "putop" + for the details. + + Braces '{' and '}', and vertical bars '|', indicate alternative + mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel + modes. In cases where there are only two alternatives, the X86_64 + instruction is reserved, and "(bad)" is printed. +*/ + +static const struct dis386 dis386[] = { + /* 00 */ + { "addB", { Eb, Gb } }, + { "addS", { Ev, Gv } }, + { "addB", { Gb, Eb } }, + { "addS", { Gv, Ev } }, + { "addB", { AL, Ib } }, + { "addS", { eAX, Iv } }, + { "push{T|}", { es } }, + { "pop{T|}", { es } }, + /* 08 */ + { "orB", { Eb, Gb } }, + { "orS", { Ev, Gv } }, + { "orB", { Gb, Eb } }, + { "orS", { Gv, Ev } }, + { "orB", { AL, Ib } }, + { "orS", { eAX, Iv } }, + { "push{T|}", { cs } }, + { "(bad)", { XX } }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcB", { Eb, Gb } }, + { "adcS", { Ev, Gv } }, + { "adcB", { Gb, Eb } }, + { "adcS", { Gv, Ev } }, + { "adcB", { AL, Ib } }, + { "adcS", { eAX, Iv } }, + { "push{T|}", { ss } }, + { "pop{T|}", { ss } }, + /* 18 */ + { "sbbB", { Eb, Gb } }, + { "sbbS", { Ev, Gv } }, + { "sbbB", { Gb, Eb } }, + { "sbbS", { Gv, Ev } }, + { "sbbB", { AL, Ib } }, + { "sbbS", { eAX, Iv } }, + { "push{T|}", { ds } }, + { "pop{T|}", { ds } }, + /* 20 */ + { "andB", { Eb, Gb } }, + { "andS", { Ev, Gv } }, + { "andB", { Gb, Eb } }, + { "andS", { Gv, Ev } }, + { "andB", { AL, Ib } }, + { "andS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG ES prefix */ + { "daa{|}", { XX } }, + /* 28 */ + { "subB", { Eb, Gb } }, + { "subS", { Ev, Gv } }, + { "subB", { Gb, Eb } }, + { "subS", { Gv, Ev } }, + { "subB", { AL, Ib } }, + { "subS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG CS prefix */ + { "das{|}", { XX } }, + /* 30 */ + { "xorB", { Eb, Gb } }, + { "xorS", { Ev, Gv } }, + { "xorB", { Gb, Eb } }, + { "xorS", { Gv, Ev } }, + { "xorB", { AL, Ib } }, + { "xorS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG SS prefix */ + { "aaa{|}", { XX } }, + /* 38 */ + { "cmpB", { Eb, Gb } }, + { "cmpS", { Ev, Gv } }, + { "cmpB", { Gb, Eb } }, + { "cmpS", { Gv, Ev } }, + { "cmpB", { AL, Ib } }, + { "cmpS", { eAX, Iv } }, + { "(bad)", { XX } }, /* SEG DS prefix */ + { "aas{|}", { XX } }, + /* 40 */ + { "inc{S|}", { RMeAX } }, + { "inc{S|}", { RMeCX } }, + { "inc{S|}", { RMeDX } }, + { "inc{S|}", { RMeBX } }, + { "inc{S|}", { RMeSP } }, + { "inc{S|}", { RMeBP } }, + { "inc{S|}", { RMeSI } }, + { "inc{S|}", { RMeDI } }, + /* 48 */ + { "dec{S|}", { RMeAX } }, + { "dec{S|}", { RMeCX } }, + { "dec{S|}", { RMeDX } }, + { "dec{S|}", { RMeBX } }, + { "dec{S|}", { RMeSP } }, + { "dec{S|}", { RMeBP } }, + { "dec{S|}", { RMeSI } }, + { "dec{S|}", { RMeDI } }, + /* 50 */ + { "pushV", { RMrAX } }, + { "pushV", { RMrCX } }, + { "pushV", { RMrDX } }, + { "pushV", { RMrBX } }, + { "pushV", { RMrSP } }, + { "pushV", { RMrBP } }, + { "pushV", { RMrSI } }, + { "pushV", { RMrDI } }, + /* 58 */ + { "popV", { RMrAX } }, + { "popV", { RMrCX } }, + { "popV", { RMrDX } }, + { "popV", { RMrBX } }, + { "popV", { RMrSP } }, + { "popV", { RMrBP } }, + { "popV", { RMrSI } }, + { "popV", { RMrDI } }, + /* 60 */ + { X86_64_0 }, + { X86_64_1 }, + { X86_64_2 }, + { X86_64_3 }, + { "(bad)", { XX } }, /* seg fs */ + { "(bad)", { XX } }, /* seg gs */ + { "(bad)", { XX } }, /* op size prefix */ + { "(bad)", { XX } }, /* adr size prefix */ + /* 68 */ + { "pushT", { Iq } }, + { "imulS", { Gv, Ev, Iv } }, + { "pushT", { sIb } }, + { "imulS", { Gv, Ev, sIb } }, + { "ins{b||b|}", { Ybr, indirDX } }, + { "ins{R||G|}", { Yzr, indirDX } }, + { "outs{b||b|}", { indirDXr, Xb } }, + { "outs{R||G|}", { indirDXr, Xz } }, + /* 70 */ + { "joH", { Jb, XX, cond_jump_flag } }, + { "jnoH", { Jb, XX, cond_jump_flag } }, + { "jbH", { Jb, XX, cond_jump_flag } }, + { "jaeH", { Jb, XX, cond_jump_flag } }, + { "jeH", { Jb, XX, cond_jump_flag } }, + { "jneH", { Jb, XX, cond_jump_flag } }, + { "jbeH", { Jb, XX, cond_jump_flag } }, + { "jaH", { Jb, XX, cond_jump_flag } }, + /* 78 */ + { "jsH", { Jb, XX, cond_jump_flag } }, + { "jnsH", { Jb, XX, cond_jump_flag } }, + { "jpH", { Jb, XX, cond_jump_flag } }, + { "jnpH", { Jb, XX, cond_jump_flag } }, + { "jlH", { Jb, XX, cond_jump_flag } }, + { "jgeH", { Jb, XX, cond_jump_flag } }, + { "jleH", { Jb, XX, cond_jump_flag } }, + { "jgH", { Jb, XX, cond_jump_flag } }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", { XX } }, + { GRP1Ss }, + { "testB", { Eb, Gb } }, + { "testS", { Ev, Gv } }, + { "xchgB", { Eb, Gb } }, + { "xchgS", { Ev, Gv } }, + /* 88 */ + { "movB", { Eb, Gb } }, + { "movS", { Ev, Gv } }, + { "movB", { Gb, Eb } }, + { "movS", { Gv, Ev } }, + { "movD", { Sv, Sw } }, + { "leaS", { Gv, M } }, + { "movD", { Sw, Sv } }, + { GRP1a }, + /* 90 */ + { PREGRP38 }, + { "xchgS", { RMeCX, eAX } }, + { "xchgS", { RMeDX, eAX } }, + { "xchgS", { RMeBX, eAX } }, + { "xchgS", { RMeSP, eAX } }, + { "xchgS", { RMeBP, eAX } }, + { "xchgS", { RMeSI, eAX } }, + { "xchgS", { RMeDI, eAX } }, + /* 98 */ + { "cW{t||t|}R", { XX } }, + { "cR{t||t|}O", { XX } }, + { "Jcall{T|}", { Ap } }, + { "(bad)", { XX } }, /* fwait */ + { "pushfT", { XX } }, + { "popfT", { XX } }, + { "sahf{|}", { XX } }, + { "lahf{|}", { XX } }, + /* a0 */ + { "movB", { AL, Ob } }, + { "movS", { eAX, Ov } }, + { "movB", { Ob, AL } }, + { "movS", { Ov, eAX } }, + { "movs{b||b|}", { Ybr, Xb } }, + { "movs{R||R|}", { Yvr, Xv } }, + { "cmps{b||b|}", { Xb, Yb } }, + { "cmps{R||R|}", { Xv, Yv } }, + /* a8 */ + { "testB", { AL, Ib } }, + { "testS", { eAX, Iv } }, + { "stosB", { Ybr, AL } }, + { "stosS", { Yvr, eAX } }, + { "lodsB", { ALr, Xb } }, + { "lodsS", { eAXr, Xv } }, + { "scasB", { AL, Yb } }, + { "scasS", { eAX, Yv } }, + /* b0 */ + { "movB", { RMAL, Ib } }, + { "movB", { RMCL, Ib } }, + { "movB", { RMDL, Ib } }, + { "movB", { RMBL, Ib } }, + { "movB", { RMAH, Ib } }, + { "movB", { RMCH, Ib } }, + { "movB", { RMDH, Ib } }, + { "movB", { RMBH, Ib } }, + /* b8 */ + { "movS", { RMeAX, Iv64 } }, + { "movS", { RMeCX, Iv64 } }, + { "movS", { RMeDX, Iv64 } }, + { "movS", { RMeBX, Iv64 } }, + { "movS", { RMeSP, Iv64 } }, + { "movS", { RMeBP, Iv64 } }, + { "movS", { RMeSI, Iv64 } }, + { "movS", { RMeDI, Iv64 } }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "retT", { Iw } }, + { "retT", { XX } }, + { "les{S|}", { Gv, Mp } }, + { "ldsS", { Gv, Mp } }, + { GRP11_C6 }, + { GRP11_C7 }, + /* c8 */ + { "enterT", { Iw, Ib } }, + { "leaveT", { XX } }, + { "lretP", { Iw } }, + { "lretP", { XX } }, + { "int3", { XX } }, + { "int", { Ib } }, + { "into{|}", { XX } }, + { "iretP", { XX } }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam{|}", { sIb } }, + { "aad{|}", { sIb } }, + { "(bad)", { XX } }, + { "xlat", { DSBX } }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopneFH", { Jb, XX, loop_jcxz_flag } }, + { "loopeFH", { Jb, XX, loop_jcxz_flag } }, + { "loopFH", { Jb, XX, loop_jcxz_flag } }, + { "jEcxzH", { Jb, XX, loop_jcxz_flag } }, + { "inB", { AL, Ib } }, + { "inG", { zAX, Ib } }, + { "outB", { Ib, AL } }, + { "outG", { Ib, zAX } }, + /* e8 */ + { "callT", { Jv } }, + { "jmpT", { Jv } }, + { "Jjmp{T|}", { Ap } }, + { "jmp", { Jb } }, + { "inB", { AL, indirDX } }, + { "inG", { zAX, indirDX } }, + { "outB", { indirDX, AL } }, + { "outG", { indirDX, zAX } }, + /* f0 */ + { "(bad)", { XX } }, /* lock prefix */ + { "icebp", { XX } }, + { "(bad)", { XX } }, /* repne */ + { "(bad)", { XX } }, /* repz */ + { "hlt", { XX } }, + { "cmc", { XX } }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", { XX } }, + { "stc", { XX } }, + { "cli", { XX } }, + { "sti", { XX } }, + { "cld", { XX } }, + { "std", { XX } }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", { Gv, Ew } }, + { "lslS", { Gv, Ew } }, + { "(bad)", { XX } }, + { "syscall", { XX } }, + { "clts", { XX } }, + { "sysretP", { XX } }, + /* 08 */ + { "invd", { XX } }, + { "wbinvd", { XX } }, + { "(bad)", { XX } }, + { "ud2a", { XX } }, + { "(bad)", { XX } }, + { GRPAMD }, + { "femms", { XX } }, + { "", { MX, EM, OPSUF } }, /* See OP_3DNowSuffix. */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { PREGRP30 }, + { "movlpX", { EXq, XM, { SIMD_Fixup, 'h' } } }, + { "unpcklpX", { XM, EXq } }, + { "unpckhpX", { XM, EXq } }, + { PREGRP31 }, + { "movhpX", { EXq, XM, { SIMD_Fixup, 'l' } } }, + /* 18 */ + { GRP16 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "nopQ", { Ev } }, + /* 20 */ + { "movZ", { Rm, Cm } }, + { "movZ", { Rm, Dm } }, + { "movZ", { Cm, Rm } }, + { "movZ", { Dm, Rm } }, + { "movL", { Rd, Td } }, + { "(bad)", { XX } }, + { "movL", { Td, Rd } }, + { "(bad)", { XX } }, + /* 28 */ + { "movapX", { XM, EXx } }, + { "movapX", { EXx, XM } }, + { PREGRP2 }, + { PREGRP33 }, + { PREGRP4 }, + { PREGRP3 }, + { PREGRP93 }, + { PREGRP94 }, + /* 30 */ + { "wrmsr", { XX } }, + { "rdtsc", { XX } }, + { "rdmsr", { XX } }, + { "rdpmc", { XX } }, + { "sysenter", { XX } }, + { "sysexit", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 38 */ + { THREE_BYTE_0 }, + { "(bad)", { XX } }, + { THREE_BYTE_1 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 40 */ + { "cmovo", { Gv, Ev } }, + { "cmovno", { Gv, Ev } }, + { "cmovb", { Gv, Ev } }, + { "cmovae", { Gv, Ev } }, + { "cmove", { Gv, Ev } }, + { "cmovne", { Gv, Ev } }, + { "cmovbe", { Gv, Ev } }, + { "cmova", { Gv, Ev } }, + /* 48 */ + { "cmovs", { Gv, Ev } }, + { "cmovns", { Gv, Ev } }, + { "cmovp", { Gv, Ev } }, + { "cmovnp", { Gv, Ev } }, + { "cmovl", { Gv, Ev } }, + { "cmovge", { Gv, Ev } }, + { "cmovle", { Gv, Ev } }, + { "cmovg", { Gv, Ev } }, + /* 50 */ + { "movmskpX", { Gdq, XS } }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andpX", { XM, EXx } }, + { "andnpX", { XM, EXx } }, + { "orpX", { XM, EXx } }, + { "xorpX", { XM, EXx } }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { PREGRP17 }, + { PREGRP16 }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { PREGRP95 }, + { PREGRP96 }, + { PREGRP97 }, + { "packsswb", { MX, EM } }, + { "pcmpgtb", { MX, EM } }, + { "pcmpgtw", { MX, EM } }, + { "pcmpgtd", { MX, EM } }, + { "packuswb", { MX, EM } }, + /* 68 */ + { "punpckhbw", { MX, EM } }, + { "punpckhwd", { MX, EM } }, + { "punpckhdq", { MX, EM } }, + { "packssdw", { MX, EM } }, + { PREGRP26 }, + { PREGRP24 }, + { "movd", { MX, Edq } }, + { PREGRP19 }, + /* 70 */ + { PREGRP22 }, + { GRP12 }, + { GRP13 }, + { GRP14 }, + { "pcmpeqb", { MX, EM } }, + { "pcmpeqw", { MX, EM } }, + { "pcmpeqd", { MX, EM } }, + { "emms", { XX } }, + /* 78 */ + { PREGRP34 }, + { PREGRP35 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP28 }, + { PREGRP29 }, + { PREGRP23 }, + { PREGRP20 }, + /* 80 */ + { "joH", { Jv, XX, cond_jump_flag } }, + { "jnoH", { Jv, XX, cond_jump_flag } }, + { "jbH", { Jv, XX, cond_jump_flag } }, + { "jaeH", { Jv, XX, cond_jump_flag } }, + { "jeH", { Jv, XX, cond_jump_flag } }, + { "jneH", { Jv, XX, cond_jump_flag } }, + { "jbeH", { Jv, XX, cond_jump_flag } }, + { "jaH", { Jv, XX, cond_jump_flag } }, + /* 88 */ + { "jsH", { Jv, XX, cond_jump_flag } }, + { "jnsH", { Jv, XX, cond_jump_flag } }, + { "jpH", { Jv, XX, cond_jump_flag } }, + { "jnpH", { Jv, XX, cond_jump_flag } }, + { "jlH", { Jv, XX, cond_jump_flag } }, + { "jgeH", { Jv, XX, cond_jump_flag } }, + { "jleH", { Jv, XX, cond_jump_flag } }, + { "jgH", { Jv, XX, cond_jump_flag } }, + /* 90 */ + { "seto", { Eb } }, + { "setno", { Eb } }, + { "setb", { Eb } }, + { "setae", { Eb } }, + { "sete", { Eb } }, + { "setne", { Eb } }, + { "setbe", { Eb } }, + { "seta", { Eb } }, + /* 98 */ + { "sets", { Eb } }, + { "setns", { Eb } }, + { "setp", { Eb } }, + { "setnp", { Eb } }, + { "setl", { Eb } }, + { "setge", { Eb } }, + { "setle", { Eb } }, + { "setg", { Eb } }, + /* a0 */ + { "pushT", { fs } }, + { "popT", { fs } }, + { "cpuid", { XX } }, + { "btS", { Ev, Gv } }, + { "shldS", { Ev, Gv, Ib } }, + { "shldS", { Ev, Gv, CL } }, + { GRPPADLCK2 }, + { GRPPADLCK1 }, + /* a8 */ + { "pushT", { gs } }, + { "popT", { gs } }, + { "rsm", { XX } }, + { "btsS", { Ev, Gv } }, + { "shrdS", { Ev, Gv, Ib } }, + { "shrdS", { Ev, Gv, CL } }, + { GRP15 }, + { "imulS", { Gv, Ev } }, + /* b0 */ + { "cmpxchgB", { Eb, Gb } }, + { "cmpxchgS", { Ev, Gv } }, + { "lssS", { Gv, Mp } }, + { "btrS", { Ev, Gv } }, + { "lfsS", { Gv, Mp } }, + { "lgsS", { Gv, Mp } }, + { "movz{bR|x|bR|x}", { Gv, Eb } }, + { "movz{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movzww ! */ + /* b8 */ + { PREGRP37 }, + { "ud2b", { XX } }, + { GRP8 }, + { "btcS", { Ev, Gv } }, + { "bsfS", { Gv, Ev } }, + { PREGRP36 }, + { "movs{bR|x|bR|x}", { Gv, Eb } }, + { "movs{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movsww ! */ + /* c0 */ + { "xaddB", { Eb, Gb } }, + { "xaddS", { Ev, Gv } }, + { PREGRP1 }, + { "movntiS", { Ev, Gv } }, + { "pinsrw", { MX, Edqw, Ib } }, + { "pextrw", { Gdq, MS, Ib } }, + { "shufpX", { XM, EXx, Ib } }, + { GRP9 }, + /* c8 */ + { "bswap", { RMeAX } }, + { "bswap", { RMeCX } }, + { "bswap", { RMeDX } }, + { "bswap", { RMeBX } }, + { "bswap", { RMeSP } }, + { "bswap", { RMeBP } }, + { "bswap", { RMeSI } }, + { "bswap", { RMeDI } }, + /* d0 */ + { PREGRP27 }, + { "psrlw", { MX, EM } }, + { "psrld", { MX, EM } }, + { "psrlq", { MX, EM } }, + { "paddq", { MX, EM } }, + { "pmullw", { MX, EM } }, + { PREGRP21 }, + { "pmovmskb", { Gdq, MS } }, + /* d8 */ + { "psubusb", { MX, EM } }, + { "psubusw", { MX, EM } }, + { "pminub", { MX, EM } }, + { "pand", { MX, EM } }, + { "paddusb", { MX, EM } }, + { "paddusw", { MX, EM } }, + { "pmaxub", { MX, EM } }, + { "pandn", { MX, EM } }, + /* e0 */ + { "pavgb", { MX, EM } }, + { "psraw", { MX, EM } }, + { "psrad", { MX, EM } }, + { "pavgw", { MX, EM } }, + { "pmulhuw", { MX, EM } }, + { "pmulhw", { MX, EM } }, + { PREGRP15 }, + { PREGRP25 }, + /* e8 */ + { "psubsb", { MX, EM } }, + { "psubsw", { MX, EM } }, + { "pminsw", { MX, EM } }, + { "por", { MX, EM } }, + { "paddsb", { MX, EM } }, + { "paddsw", { MX, EM } }, + { "pmaxsw", { MX, EM } }, + { "pxor", { MX, EM } }, + /* f0 */ + { PREGRP32 }, + { "psllw", { MX, EM } }, + { "pslld", { MX, EM } }, + { "psllq", { MX, EM } }, + { "pmuludq", { MX, EM } }, + { "pmaddwd", { MX, EM } }, + { "psadbw", { MX, EM } }, + { PREGRP18 }, + /* f8 */ + { "psubb", { MX, EM } }, + { "psubw", { MX, EM } }, + { "psubd", { MX, EM } }, + { "psubq", { MX, EM } }, + { "paddb", { MX, EM } }, + { "paddw", { MX, EM } }, + { "paddd", { MX, EM } }, + { "(bad)", { XX } }, +}; + +static const unsigned char onebyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */ + /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses DATA prefix. */ +static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */ + /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */ + /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */ + /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix. */ +static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 38 XX uses REPZ prefix. */ +static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses DATA prefix. */ +static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */ + /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix. */ +static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +/* This is used to determine if opcode 0f 3a XX uses REPZ prefix. */ +static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *insn_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static struct + { + int mod; + int reg; + int rm; + } +modrm; +static unsigned char need_modrm; + +/* If we are accessing mod/rm/reg without need_modrm set, then the + values are stale. Hitting this abort likely indicates that you + need to update onebyte_has_modrm or twobyte_has_modrm. */ +#define MODRM_CHECK if (!need_modrm) abort () + +static const char * const *names64; +static const char * const *names32; +static const char * const *names16; +static const char * const *names8; +static const char * const *names8rex; +static const char * const *names_seg; +static const char * const *index16; + +static const char * const intel_names64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; +static const char * const intel_names32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" +}; +static const char * const intel_names16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" +}; +static const char * const intel_names8[] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", +}; +static const char * const intel_names8rex[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" +}; +static const char * const intel_names_seg[] = { + "es", "cs", "ss", "ds", "fs", "gs", "?", "?", +}; +static const char * const intel_index16[] = { + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" +}; + +static const char * const att_names64[] = { + "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +}; +static const char * const att_names32[] = { + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" +}; +static const char * const att_names16[] = { + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" +}; +static const char * const att_names8[] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", +}; +static const char * const att_names8rex[] = { + "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" +}; +static const char * const att_names_seg[] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", +}; +static const char * const att_index16[] = { + "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" +}; + +static const struct dis386 grps[][8] = { + /* GRP1a */ + { + { "popU", { stackEv } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP1b */ + { + { "addA", { Eb, Ib } }, + { "orA", { Eb, Ib } }, + { "adcA", { Eb, Ib } }, + { "sbbA", { Eb, Ib } }, + { "andA", { Eb, Ib } }, + { "subA", { Eb, Ib } }, + { "xorA", { Eb, Ib } }, + { "cmpA", { Eb, Ib } }, + }, + /* GRP1S */ + { + { "addQ", { Ev, Iv } }, + { "orQ", { Ev, Iv } }, + { "adcQ", { Ev, Iv } }, + { "sbbQ", { Ev, Iv } }, + { "andQ", { Ev, Iv } }, + { "subQ", { Ev, Iv } }, + { "xorQ", { Ev, Iv } }, + { "cmpQ", { Ev, Iv } }, + }, + /* GRP1Ss */ + { + { "addQ", { Ev, sIb } }, + { "orQ", { Ev, sIb } }, + { "adcQ", { Ev, sIb } }, + { "sbbQ", { Ev, sIb } }, + { "andQ", { Ev, sIb } }, + { "subQ", { Ev, sIb } }, + { "xorQ", { Ev, sIb } }, + { "cmpQ", { Ev, sIb } }, + }, + /* GRP2b */ + { + { "rolA", { Eb, Ib } }, + { "rorA", { Eb, Ib } }, + { "rclA", { Eb, Ib } }, + { "rcrA", { Eb, Ib } }, + { "shlA", { Eb, Ib } }, + { "shrA", { Eb, Ib } }, + { "(bad)", { XX } }, + { "sarA", { Eb, Ib } }, + }, + /* GRP2S */ + { + { "rolQ", { Ev, Ib } }, + { "rorQ", { Ev, Ib } }, + { "rclQ", { Ev, Ib } }, + { "rcrQ", { Ev, Ib } }, + { "shlQ", { Ev, Ib } }, + { "shrQ", { Ev, Ib } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, Ib } }, + }, + /* GRP2b_one */ + { + { "rolA", { Eb, I1 } }, + { "rorA", { Eb, I1 } }, + { "rclA", { Eb, I1 } }, + { "rcrA", { Eb, I1 } }, + { "shlA", { Eb, I1 } }, + { "shrA", { Eb, I1 } }, + { "(bad)", { XX } }, + { "sarA", { Eb, I1 } }, + }, + /* GRP2S_one */ + { + { "rolQ", { Ev, I1 } }, + { "rorQ", { Ev, I1 } }, + { "rclQ", { Ev, I1 } }, + { "rcrQ", { Ev, I1 } }, + { "shlQ", { Ev, I1 } }, + { "shrQ", { Ev, I1 } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, I1 } }, + }, + /* GRP2b_cl */ + { + { "rolA", { Eb, CL } }, + { "rorA", { Eb, CL } }, + { "rclA", { Eb, CL } }, + { "rcrA", { Eb, CL } }, + { "shlA", { Eb, CL } }, + { "shrA", { Eb, CL } }, + { "(bad)", { XX } }, + { "sarA", { Eb, CL } }, + }, + /* GRP2S_cl */ + { + { "rolQ", { Ev, CL } }, + { "rorQ", { Ev, CL } }, + { "rclQ", { Ev, CL } }, + { "rcrQ", { Ev, CL } }, + { "shlQ", { Ev, CL } }, + { "shrQ", { Ev, CL } }, + { "(bad)", { XX } }, + { "sarQ", { Ev, CL } }, + }, + /* GRP3b */ + { + { "testA", { Eb, Ib } }, + { "(bad)", { Eb } }, + { "notA", { Eb } }, + { "negA", { Eb } }, + { "mulA", { Eb } }, /* Don't print the implicit %al register, */ + { "imulA", { Eb } }, /* to distinguish these opcodes from other */ + { "divA", { Eb } }, /* mul/imul opcodes. Do the same for div */ + { "idivA", { Eb } }, /* and idiv for consistency. */ + }, + /* GRP3S */ + { + { "testQ", { Ev, Iv } }, + { "(bad)", { XX } }, + { "notQ", { Ev } }, + { "negQ", { Ev } }, + { "mulQ", { Ev } }, /* Don't print the implicit register. */ + { "imulQ", { Ev } }, + { "divQ", { Ev } }, + { "idivQ", { Ev } }, + }, + /* GRP4 */ + { + { "incA", { Eb } }, + { "decA", { Eb } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP5 */ + { + { "incQ", { Ev } }, + { "decQ", { Ev } }, + { "callT", { indirEv } }, + { "JcallT", { indirEp } }, + { "jmpT", { indirEv } }, + { "JjmpT", { indirEp } }, + { "pushU", { stackEv } }, + { "(bad)", { XX } }, + }, + /* GRP6 */ + { + { "sldtD", { Sv } }, + { "strD", { Sv } }, + { "lldt", { Ew } }, + { "ltr", { Ew } }, + { "verr", { Ew } }, + { "verw", { Ew } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP7 */ + { + { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } }, + { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } }, + { "lgdt{Q|Q||}", { M } }, + { "lidt{Q|Q||}", { { SVME_Fixup, 0 } } }, + { "smswD", { Sv } }, + { "(bad)", { XX } }, + { "lmsw", { Ew } }, + { "invlpg", { { INVLPG_Fixup, w_mode } } }, + }, + /* GRP8 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "btQ", { Ev, Ib } }, + { "btsQ", { Ev, Ib } }, + { "btrQ", { Ev, Ib } }, + { "btcQ", { Ev, Ib } }, + }, + /* GRP9 */ + { + { "(bad)", { XX } }, + { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "", { VM } }, /* See OP_VMX. */ + { "vmptrst", { Mq } }, + }, + /* GRP11_C6 */ + { + { "movA", { Eb, Ib } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP11_C7 */ + { + { "movQ", { Ev, Iv } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRP12 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrlw", { MS, Ib } }, + { "(bad)", { XX } }, + { "psraw", { MS, Ib } }, + { "(bad)", { XX } }, + { "psllw", { MS, Ib } }, + { "(bad)", { XX } }, + }, + /* GRP13 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrld", { MS, Ib } }, + { "(bad)", { XX } }, + { "psrad", { MS, Ib } }, + { "(bad)", { XX } }, + { "pslld", { MS, Ib } }, + { "(bad)", { XX } }, + }, + /* GRP14 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psrlq", { MS, Ib } }, + { "psrldq", { MS, Ib } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "psllq", { MS, Ib } }, + { "pslldq", { MS, Ib } }, + }, + /* GRP15 */ + { + { "fxsave", { Ev } }, + { "fxrstor", { Ev } }, + { "ldmxcsr", { Ev } }, + { "stmxcsr", { Ev } }, + { "(bad)", { XX } }, + { "lfence", { { OP_0fae, 0 } } }, + { "mfence", { { OP_0fae, 0 } } }, + { "clflush", { { OP_0fae, 0 } } }, + }, + /* GRP16 */ + { + { "prefetchnta", { Ev } }, + { "prefetcht0", { Ev } }, + { "prefetcht1", { Ev } }, + { "prefetcht2", { Ev } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRPAMD */ + { + { "prefetch", { Eb } }, + { "prefetchw", { Eb } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* GRPPADLCK1 */ + { + { "xstore-rng", { { OP_0f07, 0 } } }, + { "xcrypt-ecb", { { OP_0f07, 0 } } }, + { "xcrypt-cbc", { { OP_0f07, 0 } } }, + { "xcrypt-ctr", { { OP_0f07, 0 } } }, + { "xcrypt-cfb", { { OP_0f07, 0 } } }, + { "xcrypt-ofb", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + }, + /* GRPPADLCK2 */ + { + { "montmul", { { OP_0f07, 0 } } }, + { "xsha1", { { OP_0f07, 0 } } }, + { "xsha256", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + { "(bad)", { { OP_0f07, 0 } } }, + } +}; + +static const struct dis386 prefix_user_table[][4] = { + /* PREGRP0 */ + { + { "addps", { XM, EXx } }, + { "addss", { XM, EXd } }, + { "addpd", { XM, EXx } }, + { "addsd", { XM, EXq } }, + }, + /* PREGRP1 */ + { + { "", { XM, EXx, OPSIMD } }, /* See OP_SIMD_SUFFIX. */ + { "", { XM, EXx, OPSIMD } }, + { "", { XM, EXx, OPSIMD } }, + { "", { XM, EXx, OPSIMD } }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", { XM, EMC } }, + { "cvtsi2ssY", { XM, Ev } }, + { "cvtpi2pd", { XM, EMC } }, + { "cvtsi2sdY", { XM, Ev } }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", { MXC, EXx } }, + { "cvtss2siY", { Gv, EXx } }, + { "cvtpd2pi", { MXC, EXx } }, + { "cvtsd2siY", { Gv, EXx } }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", { MXC, EXx } }, + { "cvttss2siY", { Gv, EXx } }, + { "cvttpd2pi", { MXC, EXx } }, + { "cvttsd2siY", { Gv, EXx } }, + }, + /* PREGRP5 */ + { + { "divps", { XM, EXx } }, + { "divss", { XM, EXx } }, + { "divpd", { XM, EXx } }, + { "divsd", { XM, EXx } }, + }, + /* PREGRP6 */ + { + { "maxps", { XM, EXx } }, + { "maxss", { XM, EXx } }, + { "maxpd", { XM, EXx } }, + { "maxsd", { XM, EXx } }, + }, + /* PREGRP7 */ + { + { "minps", { XM, EXx } }, + { "minss", { XM, EXx } }, + { "minpd", { XM, EXx } }, + { "minsd", { XM, EXx } }, + }, + /* PREGRP8 */ + { + { "movups", { XM, EXx } }, + { "movss", { XM, EXx } }, + { "movupd", { XM, EXx } }, + { "movsd", { XM, EXx } }, + }, + /* PREGRP9 */ + { + { "movups", { EXx, XM } }, + { "movss", { EXx, XM } }, + { "movupd", { EXx, XM } }, + { "movsd", { EXx, XM } }, + }, + /* PREGRP10 */ + { + { "mulps", { XM, EXx } }, + { "mulss", { XM, EXx } }, + { "mulpd", { XM, EXx } }, + { "mulsd", { XM, EXx } }, + }, + /* PREGRP11 */ + { + { "rcpps", { XM, EXx } }, + { "rcpss", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP12 */ + { + { "rsqrtps",{ XM, EXx } }, + { "rsqrtss",{ XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP13 */ + { + { "sqrtps", { XM, EXx } }, + { "sqrtss", { XM, EXx } }, + { "sqrtpd", { XM, EXx } }, + { "sqrtsd", { XM, EXx } }, + }, + /* PREGRP14 */ + { + { "subps", { XM, EXx } }, + { "subss", { XM, EXx } }, + { "subpd", { XM, EXx } }, + { "subsd", { XM, EXx } }, + }, + /* PREGRP15 */ + { + { "(bad)", { XM, EXx } }, + { "cvtdq2pd", { XM, EXq } }, + { "cvttpd2dq", { XM, EXx } }, + { "cvtpd2dq", { XM, EXx } }, + }, + /* PREGRP16 */ + { + { "cvtdq2ps", { XM, EXx } }, + { "cvttps2dq", { XM, EXx } }, + { "cvtps2dq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP17 */ + { + { "cvtps2pd", { XM, EXq } }, + { "cvtss2sd", { XM, EXx } }, + { "cvtpd2ps", { XM, EXx } }, + { "cvtsd2ss", { XM, EXx } }, + }, + /* PREGRP18 */ + { + { "maskmovq", { MX, MS } }, + { "(bad)", { XM, EXx } }, + { "maskmovdqu", { XM, XS } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP19 */ + { + { "movq", { MX, EM } }, + { "movdqu", { XM, EXx } }, + { "movdqa", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP20 */ + { + { "movq", { EM, MX } }, + { "movdqu", { EXx, XM } }, + { "movdqa", { EXx, XM } }, + { "(bad)", { EXx, XM } }, + }, + /* PREGRP21 */ + { + { "(bad)", { EXx, XM } }, + { "movq2dq",{ XM, MS } }, + { "movq", { EXx, XM } }, + { "movdq2q",{ MX, XS } }, + }, + /* PREGRP22 */ + { + { "pshufw", { MX, EM, Ib } }, + { "pshufhw",{ XM, EXx, Ib } }, + { "pshufd", { XM, EXx, Ib } }, + { "pshuflw",{ XM, EXx, Ib } }, + }, + /* PREGRP23 */ + { + { "movd", { Edq, MX } }, + { "movq", { XM, EXx } }, + { "movd", { Edq, XM } }, + { "(bad)", { Ed, XM } }, + }, + /* PREGRP24 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "punpckhqdq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP25 */ + { + { "movntq", { EM, MX } }, + { "(bad)", { EM, XM } }, + { "movntdq",{ EM, XM } }, + { "(bad)", { EM, XM } }, + }, + /* PREGRP26 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "punpcklqdq", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + }, + /* PREGRP27 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "addsubpd", { XM, EXx } }, + { "addsubps", { XM, EXx } }, + }, + /* PREGRP28 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "haddpd", { XM, EXx } }, + { "haddps", { XM, EXx } }, + }, + /* PREGRP29 */ + { + { "(bad)", { MX, EXx } }, + { "(bad)", { XM, EXx } }, + { "hsubpd", { XM, EXx } }, + { "hsubps", { XM, EXx } }, + }, + /* PREGRP30 */ + { + { "movlpX", { XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */ + { "movsldup", { XM, EXx } }, + { "movlpd", { XM, EXq } }, + { "movddup", { XM, EXq } }, + }, + /* PREGRP31 */ + { + { "movhpX", { XM, EXq, { SIMD_Fixup, 'l' } } }, + { "movshdup", { XM, EXx } }, + { "movhpd", { XM, EXq } }, + { "(bad)", { XM, EXq } }, + }, + /* PREGRP32 */ + { + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "(bad)", { XM, EXx } }, + { "lddqu", { XM, M } }, + }, + /* PREGRP33 */ + { + {"movntps", { Ev, XM } }, + {"movntss", { Ev, XM } }, + {"movntpd", { Ev, XM } }, + {"movntsd", { Ev, XM } }, + }, + + /* PREGRP34 */ + { + {"vmread", { Em, Gm } }, + {"(bad)", { XX } }, + {"extrq", { XS, Ib, Ib } }, + {"insertq", { XM, XS, Ib, Ib } }, + }, + + /* PREGRP35 */ + { + {"vmwrite", { Gm, Em } }, + {"(bad)", { XX } }, + {"extrq", { XM, XS } }, + {"insertq", { XM, XS } }, + }, + + /* PREGRP36 */ + { + { "bsrS", { Gv, Ev } }, + { "lzcntS", { Gv, Ev } }, + { "bsrS", { Gv, Ev } }, + { "(bad)", { XX } }, + }, + + /* PREGRP37 */ + { + { "(bad)", { XX } }, + { "popcntS", { Gv, Ev } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + + /* PREGRP38 */ + { + { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, + { "pause", { XX } }, + { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, + { "(bad)", { XX } }, + }, + + /* PREGRP39 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pblendvb", {XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP40 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendvps", {XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP41 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendvpd", { XM, EXx, XMM0 } }, + { "(bad)", { XX } }, + }, + + /* PREGRP42 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "ptest", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP43 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP44 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP45 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxbq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP46 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxwd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP47 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxwq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP48 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovsxdq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP49 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmuldq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP50 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpeqq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP51 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "movntdqa", { XM, EM } }, + { "(bad)", { XX } }, + }, + + /* PREGRP52 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "packusdw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP53 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP54 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP55 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxbq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP56 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxwd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP57 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxwq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP58 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmovzxdq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP59 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminsb", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP60 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminsd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP61 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP62 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pminud", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP63 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxsb", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP64 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxsd", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP65 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP66 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmaxud", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP67 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pmulld", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP68 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "phminposuw", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP69 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP70 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundpd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP71 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundss", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP72 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "roundsd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP73 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP74 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "blendpd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP75 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pblendw", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP76 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrb", { Edqb, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP77 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrw", { Edqw, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP78 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pextrK", { Edq, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP79 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "extractps", { Edqd, XM, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP80 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pinsrb", { XM, Edqb, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP81 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "insertps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP82 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pinsrK", { XM, Edq, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP83 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "dpps", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP84 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "dppd", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP85 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "mpsadbw", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP86 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpgtq", { XM, EXx } }, + { "(bad)", { XX } }, + }, + + /* PREGRP87 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "crc32", { Gdq, { CRC32_Fixup, b_mode } } }, + }, + + /* PREGRP88 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "crc32", { Gdq, { CRC32_Fixup, v_mode } } }, + }, + + /* PREGRP89 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpestrm", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP90 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpestri", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP91 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpistrm", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP92 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pcmpistri", { XM, EXx, Ib } }, + { "(bad)", { XX } }, + }, + + /* PREGRP93 */ + { + { "ucomiss",{ XM, EXd } }, + { "(bad)", { XX } }, + { "ucomisd",{ XM, EXq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP94 */ + { + { "comiss", { XM, EXd } }, + { "(bad)", { XX } }, + { "comisd", { XM, EXq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP95 */ + { + { "punpcklbw",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpcklbw",{ MX, EMq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP96 */ + { + { "punpcklwd",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpcklwd",{ MX, EMq } }, + { "(bad)", { XX } }, + }, + + /* PREGRP97 */ + { + { "punpckldq",{ MX, EMd } }, + { "(bad)", { XX } }, + { "punpckldq",{ MX, EMq } }, + { "(bad)", { XX } }, + }, +}; + +static const struct dis386 x86_64_table[][2] = { + { + { "pusha{P|}", { XX } }, + { "(bad)", { XX } }, + }, + { + { "popa{P|}", { XX } }, + { "(bad)", { XX } }, + }, + { + { "bound{S|}", { Gv, Ma } }, + { "(bad)", { XX } }, + }, + { + { "arpl", { Ew, Gw } }, + { "movs{||lq|xd}", { Gv, Ed } }, + }, +}; + +static const struct dis386 three_byte_table[][256] = { + /* THREE_BYTE_0 */ + { + /* 00 */ + { "pshufb", { MX, EM } }, + { "phaddw", { MX, EM } }, + { "phaddd", { MX, EM } }, + { "phaddsw", { MX, EM } }, + { "pmaddubsw", { MX, EM } }, + { "phsubw", { MX, EM } }, + { "phsubd", { MX, EM } }, + { "phsubsw", { MX, EM } }, + /* 08 */ + { "psignb", { MX, EM } }, + { "psignw", { MX, EM } }, + { "psignd", { MX, EM } }, + { "pmulhrsw", { MX, EM } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 10 */ + { PREGRP39 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP40 }, + { PREGRP41 }, + { "(bad)", { XX } }, + { PREGRP42 }, + /* 18 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "pabsb", { MX, EM } }, + { "pabsw", { MX, EM } }, + { "pabsd", { MX, EM } }, + { "(bad)", { XX } }, + /* 20 */ + { PREGRP43 }, + { PREGRP44 }, + { PREGRP45 }, + { PREGRP46 }, + { PREGRP47 }, + { PREGRP48 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 28 */ + { PREGRP49 }, + { PREGRP50 }, + { PREGRP51 }, + { PREGRP52 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 30 */ + { PREGRP53 }, + { PREGRP54 }, + { PREGRP55 }, + { PREGRP56 }, + { PREGRP57 }, + { PREGRP58 }, + { "(bad)", { XX } }, + { PREGRP86 }, + /* 38 */ + { PREGRP59 }, + { PREGRP60 }, + { PREGRP61 }, + { PREGRP62 }, + { PREGRP63 }, + { PREGRP64 }, + { PREGRP65 }, + { PREGRP66 }, + /* 40 */ + { PREGRP67 }, + { PREGRP68 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 48 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 50 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 58 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 60 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 68 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 70 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 78 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 80 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 88 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 90 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 98 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f0 */ + { PREGRP87 }, + { PREGRP88 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* THREE_BYTE_1 */ + { + /* 00 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 08 */ + { PREGRP69 }, + { PREGRP70 }, + { PREGRP71 }, + { PREGRP72 }, + { PREGRP73 }, + { PREGRP74 }, + { PREGRP75 }, + { "palignr", { MX, EM, Ib } }, + /* 10 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { PREGRP76 }, + { PREGRP77 }, + { PREGRP78 }, + { PREGRP79 }, + /* 18 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 20 */ + { PREGRP80 }, + { PREGRP81 }, + { PREGRP82 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 28 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 30 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 38 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 40 */ + { PREGRP83 }, + { PREGRP84 }, + { PREGRP85 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 48 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 50 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 58 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 60 */ + { PREGRP89 }, + { PREGRP90 }, + { PREGRP91 }, + { PREGRP92 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 68 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 70 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 78 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 80 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 88 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 90 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* 98 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* a8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* b8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* c8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* d8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* e8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f0 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + /* f8 */ + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + } +}; + +#define INTERNAL_DISASSEMBLER_ERROR _("") + +static void +ckprefix (void) +{ + int newrex; + rex = 0; + prefixes = 0; + used_prefixes = 0; + rex_used = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + newrex = 0; + switch (*codep) + { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (address_mode == mode_64bit) + newrex = *codep; + else + return; + break; + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADDR; + break; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes || rex) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; + break; + default: + return; + } + /* Rex is ignored when followed by another prefix. */ + if (rex) + { + rex_used = rex; + return; + } + rex = newrex; + codep++; + } +} + +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (int pref, int sizeflag) +{ + static const char * const rexes [16] = + { + "rex", /* 0x40 */ + "rex.B", /* 0x41 */ + "rex.X", /* 0x42 */ + "rex.XB", /* 0x43 */ + "rex.R", /* 0x44 */ + "rex.RB", /* 0x45 */ + "rex.RX", /* 0x46 */ + "rex.RXB", /* 0x47 */ + "rex.W", /* 0x48 */ + "rex.WB", /* 0x49 */ + "rex.WX", /* 0x4a */ + "rex.WXB", /* 0x4b */ + "rex.WR", /* 0x4c */ + "rex.WRB", /* 0x4d */ + "rex.WRX", /* 0x4e */ + "rex.WRXB", /* 0x4f */ + }; + + switch (pref) + { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + return rexes [pref - 0x40]; + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + if (address_mode == mode_64bit) + return (sizeflag & AFLAG) ? "addr32" : "addr64"; + else + return (sizeflag & AFLAG) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op_out[MAX_OPERANDS][100]; +static int op_ad, op_index[MAX_OPERANDS]; +static int two_source_ops; +static bfd_vma op_address[MAX_OPERANDS]; +static bfd_vma op_riprel[MAX_OPERANDS]; +static bfd_vma start_pc; + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +int +print_insn_i386 (bfd_vma pc, disassemble_info *info) +{ + intel_syntax = -1; + + return print_insn (pc, info); +} + +static int +print_insn (bfd_vma pc, disassemble_info *info) +{ + const struct dis386 *dp; + int i; + char *op_txt[MAX_OPERANDS]; + int needcomma; + unsigned char uses_DATA_prefix, uses_LOCK_prefix; + unsigned char uses_REPNZ_prefix, uses_REPZ_prefix; + int sizeflag; + const char *p; + struct dis_private priv; + unsigned char op; + + if (info->mach == bfd_mach_x86_64_intel_syntax + || info->mach == bfd_mach_x86_64) + address_mode = mode_64bit; + else + address_mode = mode_32bit; + + if (intel_syntax == (char) -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_x86_64 + || info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax) + priv.orig_sizeflag = AFLAG | DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + priv.orig_sizeflag = 0; + else + abort (); + + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86-64", 6) == 0) + { + address_mode = mode_64bit; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + address_mode = mode_32bit; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + address_mode = mode_16bit; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (address_mode == mode_64bit) + { + if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '6' && p[5] == '4') + priv.orig_sizeflag |= AFLAG; + } + else + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; + + info->private_data = &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + + obuf[0] = 0; + for (i = 0; i < MAX_OPERANDS; ++i) + { + op_out[i][0] = 0; + op_index[i] = -1; + } + + the_info = info; + start_pc = pc; + start_codep = priv.the_buffer; + codep = priv.the_buffer; + + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) + { + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) priv.the_buffer[0]); + } + + return 1; + } + + return -1; + } + + obufp = obuf; + ckprefix (); + + insn_codep = codep; + sizeflag = priv.orig_sizeflag; + + FETCH_DATA (info, codep + 1); + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + + if (((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + || (rex && rex_used)) + { + const char *name; + + /* fwait not followed by floating point instruction, or rex followed + by other prefixes. Print the first prefix. */ + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + op = 0; + if (*codep == 0x0f) + { + unsigned char threebyte; + FETCH_DATA (info, codep + 2); + threebyte = *++codep; + dp = &dis386_twobyte[threebyte]; + need_modrm = twobyte_has_modrm[*codep]; + uses_DATA_prefix = twobyte_uses_DATA_prefix[*codep]; + uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[*codep]; + uses_REPZ_prefix = twobyte_uses_REPZ_prefix[*codep]; + uses_LOCK_prefix = (*codep & ~0x02) == 0x20; + codep++; + if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) + { + FETCH_DATA (info, codep + 2); + op = *codep++; + switch (threebyte) + { + case 0x38: + uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op]; + uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op]; + uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op]; + break; + case 0x3a: + uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op]; + uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op]; + uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op]; + break; + default: + break; + } + } + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + uses_DATA_prefix = 0; + uses_REPNZ_prefix = 0; + /* pause is 0xf3 0x90. */ + uses_REPZ_prefix = *codep == 0x90; + uses_LOCK_prefix = 0; + codep++; + } + + if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ)) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + + if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax) + { + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + } + + if (!uses_DATA_prefix && (prefixes & PREFIX_DATA)) + { + sizeflag ^= DFLAG; + if (dp->op[2].bytemode == cond_jump_mode + && dp->op[0].bytemode == v_mode + && !intel_syntax) + { + if (sizeflag & DFLAG) + oappend ("data32 "); + else + oappend ("data16 "); + used_prefixes |= PREFIX_DATA; + } + } + + if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) + { + dp = &three_byte_table[dp->op[1].bytemode][op]; + modrm.mod = (*codep >> 6) & 3; + modrm.reg = (*codep >> 3) & 7; + modrm.rm = *codep & 7; + } + else if (need_modrm) + { + FETCH_DATA (info, codep + 1); + modrm.mod = (*codep >> 6) & 3; + modrm.reg = (*codep >> 3) & 7; + modrm.rm = *codep & 7; + } + + if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) + { + dofloat (sizeflag); + } + else + { + int index; + if (dp->name == NULL) + { + switch (dp->op[0].bytemode) + { + case USE_GROUPS: + dp = &grps[dp->op[1].bytemode][modrm.reg]; + break; + + case USE_PREFIX_USER_TABLE: + index = 0; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + index = 1; + else + { + /* We should check PREFIX_REPNZ and PREFIX_REPZ + before PREFIX_DATA. */ + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + index = 3; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + index = 2; + } + } + dp = &prefix_user_table[dp->op[1].bytemode][index]; + break; + + case X86_64_SPECIAL: + index = address_mode == mode_64bit ? 1 : 0; + dp = &x86_64_table[dp->op[1].bytemode][index]; + break; + + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + if (putop (dp->name, sizeflag) == 0) + { + for (i = 0; i < MAX_OPERANDS; ++i) + { + obufp = op_out[i]; + op_ad = MAX_OPERANDS - 1 - i; + if (dp->op[i].rtn) + (*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag); + } + } + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + if (rex & ~rex_used) + { + const char *name; + name = prefix_name (rex | 0x40, priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s ", name); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) + { + bfd_vma riprel; + + for (i = 0; i < MAX_OPERANDS; ++i) + op_txt[i] = op_out[i]; + + for (i = 0; i < (MAX_OPERANDS >> 1); ++i) + { + op_ad = op_index[i]; + op_index[i] = op_index[MAX_OPERANDS - 1 - i]; + op_index[MAX_OPERANDS - 1 - i] = op_ad; + riprel = op_riprel[i]; + op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i]; + op_riprel[MAX_OPERANDS - 1 - i] = riprel; + } + } + else + { + for (i = 0; i < MAX_OPERANDS; ++i) + op_txt[MAX_OPERANDS - 1 - i] = op_out[i]; + } + + needcomma = 0; + for (i = 0; i < MAX_OPERANDS; ++i) + if (*op_txt[i]) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[i] != -1 && !op_riprel[i]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info); + else + (*info->fprintf_func) (info->stream, "%s", op_txt[i]); + needcomma = 1; + } + + for (i = 0; i < MAX_OPERANDS; i++) + if (op_index[i] != -1 && op_riprel[i]) + { + (*info->fprintf_func) (info->stream, " # "); + (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + + op_address[op_index[i]]), info); + break; + } + return codep - priv.the_buffer; +} + +static const char *float_mem[] = { + /* d8 */ + "fadd{s||s|}", + "fmul{s||s|}", + "fcom{s||s|}", + "fcomp{s||s|}", + "fsub{s||s|}", + "fsubr{s||s|}", + "fdiv{s||s|}", + "fdivr{s||s|}", + /* d9 */ + "fld{s||s|}", + "(bad)", + "fst{s||s|}", + "fstp{s||s|}", + "fldenvIC", + "fldcw", + "fNstenvIC", + "fNstcw", + /* da */ + "fiadd{l||l|}", + "fimul{l||l|}", + "ficom{l||l|}", + "ficomp{l||l|}", + "fisub{l||l|}", + "fisubr{l||l|}", + "fidiv{l||l|}", + "fidivr{l||l|}", + /* db */ + "fild{l||l|}", + "fisttp{l||l|}", + "fist{l||l|}", + "fistp{l||l|}", + "(bad)", + "fld{t||t|}", + "(bad)", + "fstp{t||t|}", + /* dc */ + "fadd{l||l|}", + "fmul{l||l|}", + "fcom{l||l|}", + "fcomp{l||l|}", + "fsub{l||l|}", + "fsubr{l||l|}", + "fdiv{l||l|}", + "fdivr{l||l|}", + /* dd */ + "fld{l||l|}", + "fisttp{ll||ll|}", + "fst{l||l|}", + "fstp{l||l|}", + "frstorIC", + "(bad)", + "fNsaveIC", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "fisttp", + "fist", + "fistp", + "fbld", + "fild{ll||ll|}", + "fbstp", + "fistp{ll||ll|}", +}; + +static const unsigned char float_mem_mode[] = { + /* d8 */ + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + /* d9 */ + d_mode, + 0, + d_mode, + d_mode, + 0, + w_mode, + 0, + w_mode, + /* da */ + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + d_mode, + /* db */ + d_mode, + d_mode, + d_mode, + d_mode, + 0, + t_mode, + 0, + t_mode, + /* dc */ + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + q_mode, + /* dd */ + q_mode, + q_mode, + q_mode, + q_mode, + 0, + 0, + 0, + w_mode, + /* de */ + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + w_mode, + /* df */ + w_mode, + w_mode, + w_mode, + w_mode, + t_mode, + q_mode, + t_mode, + q_mode +}; + +#define ST { OP_ST, 0 } +#define STi { OP_STi, 0 } + +#define FGRPd9_2 NULL, { { NULL, 0 } } +#define FGRPd9_4 NULL, { { NULL, 1 } } +#define FGRPd9_5 NULL, { { NULL, 2 } } +#define FGRPd9_6 NULL, { { NULL, 3 } } +#define FGRPd9_7 NULL, { { NULL, 4 } } +#define FGRPda_5 NULL, { { NULL, 5 } } +#define FGRPdb_4 NULL, { { NULL, 6 } } +#define FGRPde_3 NULL, { { NULL, 7 } } +#define FGRPdf_4 NULL, { { NULL, 8 } } + +static const struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", { ST, STi } }, + { "fmul", { ST, STi } }, + { "fcom", { STi } }, + { "fcomp", { STi } }, + { "fsub", { ST, STi } }, + { "fsubr", { ST, STi } }, + { "fdiv", { ST, STi } }, + { "fdivr", { ST, STi } }, + }, + /* d9 */ + { + { "fld", { STi } }, + { "fxch", { STi } }, + { FGRPd9_2 }, + { "(bad)", { XX } }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", { ST, STi } }, + { "fcmove", { ST, STi } }, + { "fcmovbe",{ ST, STi } }, + { "fcmovu", { ST, STi } }, + { "(bad)", { XX } }, + { FGRPda_5 }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* db */ + { + { "fcmovnb",{ ST, STi } }, + { "fcmovne",{ ST, STi } }, + { "fcmovnbe",{ ST, STi } }, + { "fcmovnu",{ ST, STi } }, + { FGRPdb_4 }, + { "fucomi", { ST, STi } }, + { "fcomi", { ST, STi } }, + { "(bad)", { XX } }, + }, + /* dc */ + { + { "fadd", { STi, ST } }, + { "fmul", { STi, ST } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, +#if SYSV386_COMPAT + { "fsub", { STi, ST } }, + { "fsubr", { STi, ST } }, + { "fdiv", { STi, ST } }, + { "fdivr", { STi, ST } }, +#else + { "fsubr", { STi, ST } }, + { "fsub", { STi, ST } }, + { "fdivr", { STi, ST } }, + { "fdiv", { STi, ST } }, +#endif + }, + /* dd */ + { + { "ffree", { STi } }, + { "(bad)", { XX } }, + { "fst", { STi } }, + { "fstp", { STi } }, + { "fucom", { STi } }, + { "fucomp", { STi } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + }, + /* de */ + { + { "faddp", { STi, ST } }, + { "fmulp", { STi, ST } }, + { "(bad)", { XX } }, + { FGRPde_3 }, +#if SYSV386_COMPAT + { "fsubp", { STi, ST } }, + { "fsubrp", { STi, ST } }, + { "fdivp", { STi, ST } }, + { "fdivrp", { STi, ST } }, +#else + { "fsubrp", { STi, ST } }, + { "fsubp", { STi, ST } }, + { "fdivrp", { STi, ST } }, + { "fdivp", { STi, ST } }, +#endif + }, + /* df */ + { + { "ffreep", { STi } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { FGRPdf_4 }, + { "fucomip", { ST, STi } }, + { "fcomip", { ST, STi } }, + { "(bad)", { XX } }, + }, +}; + +static const char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (int sizeflag) +{ + const struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (modrm.mod != 3) + { + int fp_indx = (floatop - 0xd8) * 8 + modrm.reg; + + putop (float_mem[fp_indx], sizeflag); + obufp = op_out[0]; + op_ad = 2; + OP_E (float_mem_mode[fp_indx], sizeflag); + return; + } + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + dp = &float_reg[floatop - 0xd8][modrm.reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag); + + /* Instruction fnstsw is only one with strange arg. */ + if (floatop == 0xdf && codep[-1] == 0xe0) + pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]); + } + else + { + putop (dp->name, sizeflag); + + obufp = op_out[0]; + op_ad = 2; + if (dp->op[0].rtn) + (*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag); + + obufp = op_out[1]; + op_ad = 1; + if (dp->op[1].rtn) + (*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag); + } +} + +static void +OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + oappend ("%st" + intel_syntax); +} + +static void +OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +/* Capital letters in template are macros. */ +static int +putop (const char *template, int sizeflag) +{ + const char *p; + int alt = 0; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case '{': + alt = 0; + if (intel_syntax) + alt += 1; + if (address_mode == mode_64bit) + alt += 2; + while (alt != 0) + { + while (*++p != '|') + { + if (*p == '}') + { + /* Alternative not valid. */ + pstrcpy (obuf, sizeof(obuf), "(bad)"); + obufp = obuf + 5; + return 1; + } + else if (*p == '\0') + abort (); + } + alt--; + } + /* Fall through. */ + case 'I': + alt = 1; + continue; + case '|': + while (*++p != '}') + { + if (*p == '\0') + abort (); + } + break; + case '}': + break; + case 'A': + if (intel_syntax) + break; + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; + break; + case 'C': + if (intel_syntax && !alt) + break; + if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = intel_syntax ? 'w' : 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'D': + if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS)) + break; + USED_REX (REX_W); + if (modrm.mod == 3) + { + if (rex & REX_W) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + else + *obufp++ = 'w'; + break; + case 'E': /* For jcxz/jecxz */ + if (address_mode == mode_64bit) + { + if (sizeflag & AFLAG) + *obufp++ = 'r'; + else + *obufp++ = 'e'; + } + else + if (sizeflag & AFLAG) + *obufp++ = 'e'; + used_prefixes |= (prefixes & PREFIX_ADDR); + break; + case 'F': + if (intel_syntax) + break; + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & AFLAG) + *obufp++ = address_mode == mode_64bit ? 'q' : 'l'; + else + *obufp++ = address_mode == mode_64bit ? 'l' : 'w'; + used_prefixes |= (prefixes & PREFIX_ADDR); + } + break; + case 'G': + if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS))) + break; + if ((rex & REX_W) || (sizeflag & DFLAG)) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'H': + if (intel_syntax) + break; + if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS + || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) + { + used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); + *obufp++ = ','; + *obufp++ = 'p'; + if (prefixes & PREFIX_DS) + *obufp++ = 't'; + else + *obufp++ = 'n'; + } + break; + case 'J': + if (intel_syntax) + break; + *obufp++ = 'l'; + break; + case 'K': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else + *obufp++ = 'd'; + break; + case 'Z': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS)) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'L': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'O': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'o'; + else if (intel_syntax && (sizeflag & DFLAG)) + *obufp++ = 'q'; + else + *obufp++ = 'd'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'T': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) + || (rex & REX_W) + || (sizeflag & SUFFIX_ALWAYS)) + { + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'U': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'Q': + if (intel_syntax && !alt) + break; + USED_REX (REX_W); + if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + { + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = intel_syntax ? 'd' : 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'R': + USED_REX (REX_W); + if (rex & REX_W) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + { + if (intel_syntax) + *obufp++ = 'd'; + else + *obufp++ = 'l'; + } + else + *obufp++ = 'w'; + if (intel_syntax && !p[1] + && ((rex & REX_W) || (sizeflag & DFLAG))) + *obufp++ = 'e'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'V': + if (intel_syntax) + break; + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'S': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + { + if (rex & REX_W) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'X': + if (prefixes & PREFIX_DATA) + *obufp++ = 'd'; + else + *obufp++ = 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'Y': + if (intel_syntax) + break; + if (rex & REX_W) + { + USED_REX (REX_W); + *obufp++ = 'q'; + } + break; + /* implicit operand size 'l' for i386 or 'q' for x86-64 */ + case 'W': + /* operand size flag for cwtl, cbtw */ + USED_REX (REX_W); + if (rex & REX_W) + { + if (intel_syntax) + *obufp++ = 'd'; + else + *obufp++ = 'l'; + } + else if (sizeflag & DFLAG) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + alt = 0; + } + *obufp = 0; + return 0; +} + +static void +oappend (const char *s) +{ + strcpy (obufp, s); + obufp += strlen (s); +} + +static void +append_seg (void) +{ + if (prefixes & PREFIX_CS) + { + used_prefixes |= PREFIX_CS; + oappend ("%cs:" + intel_syntax); + } + if (prefixes & PREFIX_DS) + { + used_prefixes |= PREFIX_DS; + oappend ("%ds:" + intel_syntax); + } + if (prefixes & PREFIX_SS) + { + used_prefixes |= PREFIX_SS; + oappend ("%ss:" + intel_syntax); + } + if (prefixes & PREFIX_ES) + { + used_prefixes |= PREFIX_ES; + oappend ("%es:" + intel_syntax); + } + if (prefixes & PREFIX_FS) + { + used_prefixes |= PREFIX_FS; + oappend ("%fs:" + intel_syntax); + } + if (prefixes & PREFIX_GS) + { + used_prefixes |= PREFIX_GS; + oappend ("%gs:" + intel_syntax); + } +} + +static void +OP_indirE (int bytemode, int sizeflag) +{ + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); +} + +static void +print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) +{ + if (address_mode == mode_64bit) + { + if (hex) + { + char tmp[30]; + int i; + buf[0] = '0'; + buf[1] = 'x'; + snprintf_vma (tmp, sizeof(tmp), disp); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + pstrcpy (buf + 2, bufsize - 2, tmp + i); + } + else + { + bfd_signed_vma v = disp; + char tmp[30]; + int i; + if (v < 0) + { + *(buf++) = '-'; + v = -disp; + /* Check for possible overflow on 0x8000000000000000. */ + if (v < 0) + { + pstrcpy (buf, bufsize, "9223372036854775808"); + return; + } + } + if (!v) + { + pstrcpy (buf, bufsize, "0"); + return; + } + + i = 0; + tmp[29] = 0; + while (v) + { + tmp[28 - i] = (v % 10) + '0'; + v /= 10; + i++; + } + pstrcpy (buf, bufsize, tmp + 29 - i); + } + } + else + { + if (hex) + snprintf (buf, bufsize, "0x%x", (unsigned int) disp); + else + snprintf (buf, bufsize, "%d", (int) disp); + } +} + +/* Put DISP in BUF as signed hex number. */ + +static void +print_displacement (char *buf, bfd_vma disp) +{ + bfd_signed_vma val = disp; + char tmp[30]; + int i, j = 0; + + if (val < 0) + { + buf[j++] = '-'; + val = -disp; + + /* Check for possible overflow. */ + if (val < 0) + { + switch (address_mode) + { + case mode_64bit: + strcpy (buf + j, "0x8000000000000000"); + break; + case mode_32bit: + strcpy (buf + j, "0x80000000"); + break; + case mode_16bit: + strcpy (buf + j, "0x8000"); + break; + } + return; + } + } + + buf[j++] = '0'; + buf[j++] = 'x'; + + snprintf_vma (tmp, sizeof(tmp), val); + for (i = 0; tmp[i] == '0'; i++) + continue; + if (tmp[i] == '\0') + i--; + strcpy (buf + j, tmp + i); +} + +static void +intel_operand_size (int bytemode, int sizeflag) +{ + switch (bytemode) + { + case b_mode: + case dqb_mode: + oappend ("BYTE PTR "); + break; + case w_mode: + case dqw_mode: + oappend ("WORD PTR "); + break; + case stack_v_mode: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + oappend ("QWORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + /* FALLTHRU */ + case v_mode: + case dq_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend ("QWORD PTR "); + else if ((sizeflag & DFLAG) || bytemode == dq_mode) + oappend ("DWORD PTR "); + else + oappend ("WORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case z_mode: + if ((rex & REX_W) || (sizeflag & DFLAG)) + *obufp++ = 'D'; + oappend ("WORD PTR "); + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case d_mode: + case dqd_mode: + oappend ("DWORD PTR "); + break; + case q_mode: + oappend ("QWORD PTR "); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend ("QWORD PTR "); + else + oappend ("DWORD PTR "); + break; + case f_mode: + if (sizeflag & DFLAG) + oappend ("FWORD PTR "); + else + oappend ("DWORD PTR "); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case t_mode: + oappend ("TBYTE PTR "); + break; + case x_mode: + oappend ("XMMWORD PTR "); + break; + case o_mode: + oappend ("OWORD PTR "); + break; + default: + break; + } +} + +static void +OP_E (int bytemode, int sizeflag) +{ + bfd_vma disp; + int add = 0; + int riprel = 0; + USED_REX (REX_B); + if (rex & REX_B) + add += 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + if (modrm.mod == 3) + { + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[modrm.rm + add]); + else + oappend (names8[modrm.rm + add]); + break; + case w_mode: + oappend (names16[modrm.rm + add]); + break; + case d_mode: + oappend (names32[modrm.rm + add]); + break; + case q_mode: + oappend (names64[modrm.rm + add]); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend (names64[modrm.rm + add]); + else + oappend (names32[modrm.rm + add]); + break; + case stack_v_mode: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + oappend (names64[modrm.rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + bytemode = v_mode; + /* FALLTHRU */ + case v_mode: + case dq_mode: + case dqb_mode: + case dqd_mode: + case dqw_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.rm + add]); + else if ((sizeflag & DFLAG) || bytemode != v_mode) + oappend (names32[modrm.rm + add]); + else + oappend (names16[modrm.rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + return; + } + + disp = 0; + if (intel_syntax) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + { + /* 32/64 bit address mode */ + int havedisp; + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = modrm.rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + index = (*codep >> 3) & 7; + if (address_mode == mode_64bit || index != 0x4) + /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ + scale = (*codep >> 6) & 3; + base = *codep & 7; + USED_REX (REX_X); + if (rex & REX_X) + index += 8; + codep++; + } + base += add; + + switch (modrm.mod) + { + case 0: + if ((base & 7) == 5) + { + havebase = 0; + if (address_mode == mode_64bit && !havesib) + riprel = 1; + disp = get32s (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32s (); + break; + } + + havedisp = havebase || (havesib && (index != 4 || scale != 0)); + + if (!intel_syntax) + if (modrm.mod != 0 || (base & 7) == 5) + { + if (havedisp || riprel) + print_displacement (scratchbuf, disp); + else + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); + if (riprel) + { + set_op (disp, 1); + oappend ("(%rip)"); + } + } + + if (havedisp || (intel_syntax && riprel)) + { + *obufp++ = open_char; + if (intel_syntax && riprel) + { + set_op (disp, 1); + oappend ("rip"); + } + *obufp = '\0'; + if (havebase) + oappend (address_mode == mode_64bit && (sizeflag & AFLAG) + ? names64[base] : names32[base]); + if (havesib) + { + if (index != 4) + { + if (!intel_syntax || havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + oappend (address_mode == mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + } + if (scale != 0 || (!intel_syntax && index != 4)) + { + *obufp++ = scale_char; + *obufp = '\0'; + snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale); + oappend (scratchbuf); + } + } + if (intel_syntax + && (disp || modrm.mod != 0 || (base & 7) == 5)) + { + if ((bfd_signed_vma) disp >= 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + else if (modrm.mod != 1) + { + *obufp++ = '-'; + *obufp = '\0'; + disp = - (bfd_signed_vma) disp; + } + + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (modrm.mod != 0 || (base & 7) == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); + } + } + } + else + { /* 16 bit address mode */ + switch (modrm.mod) + { + case 0: + if (modrm.rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (!intel_syntax) + if (modrm.mod != 0 || modrm.rm == 6) + { + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + if (modrm.mod != 0 || modrm.rm != 6) + { + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[modrm.rm]); + if (intel_syntax + && (disp || modrm.mod != 0 || modrm.rm == 6)) + { + if ((bfd_signed_vma) disp >= 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + else if (modrm.mod != 1) + { + *obufp++ = '-'; + *obufp = '\0'; + disp = - (bfd_signed_vma) disp; + } + + print_displacement (scratchbuf, disp); + oappend (scratchbuf); + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, + disp & 0xffff); + oappend (scratchbuf); + } + } +} + +static void +OP_G (int bytemode, int sizeflag) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add += 8; + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[modrm.reg + add]); + else + oappend (names8[modrm.reg + add]); + break; + case w_mode: + oappend (names16[modrm.reg + add]); + break; + case d_mode: + oappend (names32[modrm.reg + add]); + break; + case q_mode: + oappend (names64[modrm.reg + add]); + break; + case v_mode: + case dq_mode: + case dqb_mode: + case dqd_mode: + case dqw_mode: + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.reg + add]); + else if ((sizeflag & DFLAG) || bytemode != v_mode) + oappend (names32[modrm.reg + add]); + else + oappend (names16[modrm.reg + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case m_mode: + if (address_mode == mode_64bit) + oappend (names64[modrm.reg + add]); + else + oappend (names32[modrm.reg + add]); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } +} + +static bfd_vma +get64 (void) +{ + bfd_vma x; +#ifdef BFD64 + unsigned int a; + unsigned int b; + + FETCH_DATA (the_info, codep + 8); + a = *codep++ & 0xff; + a |= (*codep++ & 0xff) << 8; + a |= (*codep++ & 0xff) << 16; + a |= (*codep++ & 0xff) << 24; + b = *codep++ & 0xff; + b |= (*codep++ & 0xff) << 8; + b |= (*codep++ & 0xff) << 16; + b |= (*codep++ & 0xff) << 24; + x = a + ((bfd_vma) b << 32); +#else + abort (); + x = 0; +#endif + return x; +} + +static bfd_signed_vma +get32 (void) +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + return x; +} + +static bfd_signed_vma +get32s (void) +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + + x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); + + return x; +} + +static int +get16 (void) +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return x; +} + +static void +set_op (bfd_vma op, int riprel) +{ + op_index[op_ad] = op_ad; + if (address_mode == mode_64bit) + { + op_address[op_ad] = op; + op_riprel[op_ad] = riprel; + } + else + { + /* Mask to get a 32-bit address. */ + op_address[op_ad] = op & 0xffffffff; + op_riprel[op_ad] = riprel & 0xffffffff; + } +} + +static void +OP_REG (int code, int sizeflag) +{ + const char *s; + int add = 0; + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + + switch (code) + { + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg + add]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg + add]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg + add]; + else + s = names8[code - al_reg]; + break; + case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: + case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: + if (address_mode == mode_64bit && (sizeflag & DFLAG)) + { + s = names64[code - rAX_reg + add]; + break; + } + code += eAX_reg - rAX_reg; + /* Fall through. */ + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_W); + if (rex & REX_W) + s = names64[code - eAX_reg + add]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg + add]; + else + s = names16[code - eAX_reg + add]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_IMREG (int code, int sizeflag) +{ + const char *s; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "dx"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg]; + else + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_W); + if (rex & REX_W) + s = names64[code - eAX_reg]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case z_mode_ax_reg: + if ((rex & REX_W) || (sizeflag & DFLAG)) + s = *names32; + else + s = *names16; + if (!(rex & REX_W)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case q_mode: + if (address_mode == mode_64bit) + { + op = get32s (); + break; + } + /* Fall through. */ + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + case const_1_mode: + if (intel_syntax) + oappend ("1"); + return; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_I64 (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + if (address_mode != mode_64bit) + { + OP_I (bytemode, sizeflag); + return; + } + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get64 (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (int bytemode, int sizeflag) +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + mask = 0xffffffff; + break; + case v_mode: + USED_REX (REX_W); + if (rex & REX_W) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32s (); + mask = 0xffffffff; + } + else + { + mask = 0xffffffff; + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + mask = 0xffffffff; + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_J (int bytemode, int sizeflag) +{ + bfd_vma disp; + bfd_vma mask = -1; + bfd_vma segment = 0; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if ((sizeflag & DFLAG) || (rex & REX_W)) + disp = get32s (); + else + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + /* In 16bit mode, address is wrapped around at 64k within + the same segment. Otherwise, a data16 prefix on a jump + instruction means that the pc is masked to 16 bits after + the displacement is added! */ + mask = 0xffff; + if ((prefixes & PREFIX_DATA) == 0) + segment = ((start_pc + codep - start_codep) + & ~((bfd_vma) 0xffff)); + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + disp = ((start_pc + codep - start_codep + disp) & mask) | segment; + set_op (disp, 0); + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); + oappend (scratchbuf); +} + +static void +OP_SEG (int bytemode, int sizeflag) +{ + if (bytemode == w_mode) + oappend (names_seg[modrm.reg]); + else + OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag); +} + +static void +OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) +{ + int seg, offset; + + if (sizeflag & DFLAG) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + if (intel_syntax) + snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset); + else + snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); +} + +static void +OP_OFF (int bytemode, int sizeflag) +{ + bfd_vma off; + + if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + off = get32 (); + else + off = get16 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); + oappend (scratchbuf); +} + +static void +OP_OFF64 (int bytemode, int sizeflag) +{ + bfd_vma off; + + if (address_mode != mode_64bit + || (prefixes & PREFIX_ADDR)) + { + OP_OFF (bytemode, sizeflag); + return; + } + + if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + intel_operand_size (bytemode, sizeflag); + append_seg (); + + off = get64 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); + oappend (scratchbuf); +} + +static void +ptr_reg (int code, int sizeflag) +{ + const char *s; + + *obufp++ = open_char; + used_prefixes |= (prefixes & PREFIX_ADDR); + if (address_mode == mode_64bit) + { + if (!(sizeflag & AFLAG)) + s = names32[code - eAX_reg]; + else + s = names64[code - eAX_reg]; + } + else if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + *obufp++ = close_char; + *obufp = 0; +} + +static void +OP_ESreg (int code, int sizeflag) +{ + if (intel_syntax) + { + switch (codep[-1]) + { + case 0x6d: /* insw/insl */ + intel_operand_size (z_mode, sizeflag); + break; + case 0xa5: /* movsw/movsl/movsq */ + case 0xa7: /* cmpsw/cmpsl/cmpsq */ + case 0xab: /* stosw/stosl */ + case 0xaf: /* scasw/scasl */ + intel_operand_size (v_mode, sizeflag); + break; + default: + intel_operand_size (b_mode, sizeflag); + } + } + oappend ("%es:" + intel_syntax); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (int code, int sizeflag) +{ + if (intel_syntax) + { + switch (codep[-1]) + { + case 0x6f: /* outsw/outsl */ + intel_operand_size (z_mode, sizeflag); + break; + case 0xa5: /* movsw/movsl/movsq */ + case 0xa7: /* cmpsw/cmpsl/cmpsq */ + case 0xad: /* lodsw/lodsl/lodsq */ + intel_operand_size (v_mode, sizeflag); + break; + default: + intel_operand_size (b_mode, sizeflag); + } + } + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_seg (); + ptr_reg (code, sizeflag); +} + +static void +OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + if (rex & REX_R) + { + USED_REX (REX_R); + add = 8; + } + else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK)) + { + used_prefixes |= PREFIX_LOCK; + add = 8; + } + snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + if (intel_syntax) + snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add); + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add); + oappend (scratchbuf); +} + +static void +OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_R (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + { + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); + } + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + int add = 0; + USED_REX (REX_R); + if (rex & REX_R) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EM (int bytemode, int sizeflag) +{ + if (modrm.mod != 3) + { + if (intel_syntax && bytemode == v_mode) + { + bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; + used_prefixes |= (prefixes & PREFIX_DATA); + } + OP_E (bytemode, sizeflag); + return; + } + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + { + int add = 0; + + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); + } + else + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +/* cvt* are the only instructions in sse2 which have + both SSE and MMX operands and also have 0x66 prefix + in their opcode. 0x66 was originally used to differentiate + between SSE and MMX instruction(operands). So we have to handle the + cvt* separately using OP_EMC and OP_MXC */ +static void +OP_EMC (int bytemode, int sizeflag) +{ + if (modrm.mod != 3) + { + if (intel_syntax && bytemode == v_mode) + { + bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; + used_prefixes |= (prefixes & PREFIX_DATA); + } + OP_E (bytemode, sizeflag); + return; + } + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + used_prefixes |= (prefixes & PREFIX_DATA); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + used_prefixes |= (prefixes & PREFIX_DATA); + snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EX (int bytemode, int sizeflag) +{ + int add = 0; + if (modrm.mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_B); + if (rex & REX_B) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MS (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_XS (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + OP_EX (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_M (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */ + BadOp (); + else + OP_E (bytemode, sizeflag); +} + +static void +OP_0f07 (int bytemode, int sizeflag) +{ + if (modrm.mod != 3 || modrm.rm != 0) + BadOp (); + else + OP_E (bytemode, sizeflag); +} + +static void +OP_0fae (int bytemode, int sizeflag) +{ + if (modrm.mod == 3) + { + if (modrm.reg == 7) + strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); + + if (modrm.reg < 5 || modrm.rm != 0) + { + BadOp (); /* bad sfence, mfence, or lfence */ + return; + } + } + else if (modrm.reg != 7) + { + BadOp (); /* bad clflush */ + return; + } + + OP_E (bytemode, sizeflag); +} + +/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in + 32bit mode and "xchg %rax,%rax" in 64bit mode. */ + +static void +NOP_Fixup1 (int bytemode, int sizeflag) +{ + if ((prefixes & PREFIX_DATA) != 0 + || (rex != 0 + && rex != 0x48 + && address_mode == mode_64bit)) + OP_REG (bytemode, sizeflag); + else + strcpy (obuf, "nop"); +} + +static void +NOP_Fixup2 (int bytemode, int sizeflag) +{ + if ((prefixes & PREFIX_DATA) != 0 + || (rex != 0 + && rex != 0x48 + && address_mode == mode_64bit)) + OP_IMREG (bytemode, sizeflag); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen (obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op_out[0][0] = '\0'; + op_out[1][0] = '\0'; + BadOp (); + } +} + +static const char *simd_cmp_op[] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen (obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + char suffix1 = 'p', suffix2 = 's'; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + suffix1 = 's'; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + suffix2 = 'd'; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + suffix1 = 's', suffix2 = 'd'; + } + } + snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op_out[0][0] = '\0'; + op_out[1][0] = '\0'; + BadOp (); + } +} + +static void +SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (modrm.mod == 3) + { + char *p = obuf + strlen (obuf); + *(p + 1) = '\0'; + *p = *(p - 1); + *(p - 1) = *(p - 2); + *(p - 2) = *(p - 3); + *(p - 3) = extrachar; + } +} + +static void +PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) +{ + if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1) + { + /* Override "sidt". */ + size_t olen = strlen (obuf); + char *p = obuf + olen - 4; + const char * const *names = (address_mode == mode_64bit + ? names64 : names32); + + /* We might have a suffix when disassembling with -Msuffix. */ + if (*p == 'i') + --p; + + /* Remove "addr16/addr32" if we aren't in Intel mode. */ + if (!intel_syntax + && (prefixes & PREFIX_ADDR) + && olen >= (4 + 7) + && *(p - 1) == ' ' + && strncmp (p - 7, "addr", 4) == 0 + && (strncmp (p - 3, "16", 2) == 0 + || strncmp (p - 3, "32", 2) == 0)) + p -= 7; + + if (modrm.rm) + { + /* mwait %eax,%ecx */ + strcpy (p, "mwait"); + if (!intel_syntax) + strcpy (op_out[0], names[0]); + } + else + { + /* monitor %eax,%ecx,%edx" */ + strcpy (p, "monitor"); + if (!intel_syntax) + { + const char * const *op1_names; + if (!(prefixes & PREFIX_ADDR)) + op1_names = (address_mode == mode_16bit + ? names16 : names); + else + { + op1_names = (address_mode != mode_32bit + ? names32 : names16); + used_prefixes |= PREFIX_ADDR; + } + strcpy (op_out[0], op1_names[0]); + strcpy (op_out[2], names[2]); + } + } + if (!intel_syntax) + { + strcpy (op_out[1], names[1]); + two_source_ops = 1; + } + + codep++; + } + else + OP_M (0, sizeflag); +} + +static void +SVME_Fixup (int bytemode, int sizeflag) +{ + const char *alt; + char *p; + + switch (*codep) + { + case 0xd8: + alt = "vmrun"; + break; + case 0xd9: + alt = "vmmcall"; + break; + case 0xda: + alt = "vmload"; + break; + case 0xdb: + alt = "vmsave"; + break; + case 0xdc: + alt = "stgi"; + break; + case 0xdd: + alt = "clgi"; + break; + case 0xde: + alt = "skinit"; + break; + case 0xdf: + alt = "invlpga"; + break; + default: + OP_M (bytemode, sizeflag); + return; + } + /* Override "lidt". */ + p = obuf + strlen (obuf) - 4; + /* We might have a suffix. */ + if (*p == 'i') + --p; + strcpy (p, alt); + if (!(prefixes & PREFIX_ADDR)) + { + ++codep; + return; + } + used_prefixes |= PREFIX_ADDR; + switch (*codep++) + { + case 0xdf: + strcpy (op_out[1], names32[1]); + two_source_ops = 1; + /* Fall through. */ + case 0xd8: + case 0xda: + case 0xdb: + *obufp++ = open_char; + if (address_mode == mode_64bit || (sizeflag & AFLAG)) + alt = names32[0]; + else + alt = names16[0]; + strcpy (obufp, alt); + obufp += strlen (alt); + *obufp++ = close_char; + *obufp = '\0'; + break; + } +} + +static void +INVLPG_Fixup (int bytemode, int sizeflag) +{ + const char *alt; + + switch (*codep) + { + case 0xf8: + alt = "swapgs"; + break; + case 0xf9: + alt = "rdtscp"; + break; + default: + OP_M (bytemode, sizeflag); + return; + } + /* Override "invlpg". */ + strcpy (obuf + strlen (obuf) - 6, alt); + codep++; +} + +static void +BadOp (void) +{ + /* Throw away prefixes and 1st. opcode byte. */ + codep = insn_codep + 1; + oappend ("(bad)"); +} + +static void +VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) +{ + if (modrm.mod == 3 + && modrm.reg == 0 + && modrm.rm >=1 + && modrm.rm <= 4) + { + /* Override "sgdt". */ + char *p = obuf + strlen (obuf) - 4; + + /* We might have a suffix when disassembling with -Msuffix. */ + if (*p == 'g') + --p; + + switch (modrm.rm) + { + case 1: + strcpy (p, "vmcall"); + break; + case 2: + strcpy (p, "vmlaunch"); + break; + case 3: + strcpy (p, "vmresume"); + break; + case 4: + strcpy (p, "vmxoff"); + break; + } + + codep++; + } + else + OP_E (0, sizeflag); +} + +static void +OP_VMX (int bytemode, int sizeflag) +{ + used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); + if (prefixes & PREFIX_DATA) + strcpy (obuf, "vmclear"); + else if (prefixes & PREFIX_REPZ) + strcpy (obuf, "vmxon"); + else + strcpy (obuf, "vmptrld"); + OP_E (bytemode, sizeflag); +} + +static void +REP_Fixup (int bytemode, int sizeflag) +{ + /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs, + lods and stos. */ + size_t ilen = 0; + + if (prefixes & PREFIX_REPZ) + switch (*insn_codep) + { + case 0x6e: /* outsb */ + case 0x6f: /* outsw/outsl */ + case 0xa4: /* movsb */ + case 0xa5: /* movsw/movsl/movsq */ + if (!intel_syntax) + ilen = 5; + else + ilen = 4; + break; + case 0xaa: /* stosb */ + case 0xab: /* stosw/stosl/stosq */ + case 0xac: /* lodsb */ + case 0xad: /* lodsw/lodsl/lodsq */ + if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS)) + ilen = 5; + else + ilen = 4; + break; + case 0x6c: /* insb */ + case 0x6d: /* insl/insw */ + if (!intel_syntax) + ilen = 4; + else + ilen = 3; + break; + default: + abort (); + break; + } + + if (ilen != 0) + { + size_t olen; + char *p; + + olen = strlen (obuf); + p = obuf + olen - ilen - 1 - 4; + /* Handle "repz [addr16|addr32]". */ + if ((prefixes & PREFIX_ADDR)) + p -= 1 + 6; + + memmove (p + 3, p + 4, olen - (p + 3 - obuf)); + } + + switch (bytemode) + { + case al_reg: + case eAX_reg: + case indir_dx_reg: + OP_IMREG (bytemode, sizeflag); + break; + case eDI_reg: + OP_ESreg (bytemode, sizeflag); + break; + case eSI_reg: + OP_DSreg (bytemode, sizeflag); + break; + default: + abort (); + break; + } +} + +static void +CMPXCHG8B_Fixup (int bytemode, int sizeflag) +{ + USED_REX (REX_W); + if (rex & REX_W) + { + /* Change cmpxchg8b to cmpxchg16b. */ + char *p = obuf + strlen (obuf) - 2; + strcpy (p, "16b"); + bytemode = o_mode; + } + OP_M (bytemode, sizeflag); +} + +static void +XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED) +{ + snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg); + oappend (scratchbuf + intel_syntax); +} + +static void +CRC32_Fixup (int bytemode, int sizeflag) +{ + /* Add proper suffix to "crc32". */ + char *p = obuf + strlen (obuf); + + switch (bytemode) + { + case b_mode: + if (intel_syntax) + break; + + *p++ = 'b'; + break; + case v_mode: + if (intel_syntax) + break; + + USED_REX (REX_W); + if (rex & REX_W) + *p++ = 'q'; + else if (sizeflag & DFLAG) + *p++ = 'l'; + else + *p++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + *p = '\0'; + + if (modrm.mod == 3) + { + int add; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + USED_REX (REX_B); + add = (rex & REX_B) ? 8 : 0; + if (bytemode == b_mode) + { + USED_REX (0); + if (rex) + oappend (names8rex[modrm.rm + add]); + else + oappend (names8[modrm.rm + add]); + } + else + { + USED_REX (REX_W); + if (rex & REX_W) + oappend (names64[modrm.rm + add]); + else if ((prefixes & PREFIX_DATA)) + oappend (names16[modrm.rm + add]); + else + oappend (names32[modrm.rm + add]); + } + } + else + OP_E (bytemode, sizeflag); +} diff --git a/qemu/qemu-git/i386.ld b/qemu/qemu-git/i386.ld new file mode 100644 index 0000000..f2dafec --- /dev/null +++ b/qemu/qemu-git/i386.ld @@ -0,0 +1,141 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/ia64.ld b/qemu/qemu-git/ia64.ld new file mode 100644 index 0000000..0c37796 --- /dev/null +++ b/qemu/qemu-git/ia64.ld @@ -0,0 +1,209 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little", + "elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) } + .init : + { + KEEP (*(.init)) + } =0x00300000010070000002000001000400 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x00300000010070000002000001000400 + .fini : + { + KEEP (*(.fini)) + } =0x00300000010070000002000001000400 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .opd : { *(.opd) } + .IA_64.unwind_info : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) } + .IA_64.unwind : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + /* Ensure __gp is outside the range of any normal data. We need to + do this to avoid the linker optimizing the code in op.o and getting + it out of sync with the relocs that we read when processing that + file. A better solution might be to ensure that the dynamically + generated code and static qemu code share a single gp-value. */ + __gp = . + 0x200000; + .got : { *(.got.plt) *(.got) } + .IA_64.pltoff : { *(.IA_64.pltoff) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + . += 0x400000; /* ensure .bss stuff is out of reach of gp */ + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/ioport.h b/qemu/qemu-git/ioport.h new file mode 100644 index 0000000..3d3c8a3 --- /dev/null +++ b/qemu/qemu-git/ioport.h @@ -0,0 +1,53 @@ +/* + * defines ioport related functions + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/************************************************************************** + * IO ports API + */ + +#ifndef IOPORT_H +#define IOPORT_H + +#include "qemu-common.h" + +typedef uint32_t pio_addr_t; +#define FMT_pioaddr PRIx32 + +#define MAX_IOPORTS (64 * 1024) +#define IOPORTS_MASK (MAX_IOPORTS - 1) + +/* These should really be in isa.h, but are here to make pc.h happy. */ +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); + +int register_ioport_read(pio_addr_t start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(pio_addr_t start, int length, int size, + IOPortWriteFunc *func, void *opaque); +void isa_unassign_ioport(pio_addr_t start, int length); + + +void cpu_outb(pio_addr_t addr, uint8_t val); +void cpu_outw(pio_addr_t addr, uint16_t val); +void cpu_outl(pio_addr_t addr, uint32_t val); +uint8_t cpu_inb(pio_addr_t addr); +uint16_t cpu_inw(pio_addr_t addr); +uint32_t cpu_inl(pio_addr_t addr); + +#endif /* IOPORT_H */ diff --git a/qemu/qemu-git/kvm.h b/qemu/qemu-git/kvm.h new file mode 100644 index 0000000..1c93ac5 --- /dev/null +++ b/qemu/qemu-git/kvm.h @@ -0,0 +1,142 @@ +/* + * QEMU KVM support + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_H +#define QEMU_KVM_H + +#include "config.h" +#include "qemu-queue.h" + +#ifdef CONFIG_KVM +extern int kvm_allowed; + +#define kvm_enabled() (kvm_allowed) +#else +#define kvm_enabled() (0) +#endif + +struct kvm_run; + +/* external API */ + +int kvm_init(int smp_cpus); + +int kvm_init_vcpu(CPUState *env); + +int kvm_cpu_exec(CPUState *env); + +void kvm_set_phys_mem(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset); + +int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + +int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); +int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); +int kvm_set_migration_log(int enable); + +int kvm_has_sync_mmu(void); +int kvm_has_vcpu_events(void); + +void kvm_setup_guest_memory(void *start, size_t size); + +int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); +int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); + +int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, + target_ulong len, int type); +int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, + target_ulong len, int type); +void kvm_remove_all_breakpoints(CPUState *current_env); +int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); + +int kvm_pit_in_kernel(void); +int kvm_irqchip_in_kernel(void); + +/* internal API */ + +struct KVMState; +typedef struct KVMState KVMState; + +int kvm_ioctl(KVMState *s, int type, ...); + +int kvm_vm_ioctl(KVMState *s, int type, ...); + +int kvm_vcpu_ioctl(CPUState *env, int type, ...); + +/* Arch specific hooks */ + +int kvm_arch_post_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run); + +int kvm_arch_pre_run(CPUState *env, struct kvm_run *run); + +int kvm_arch_get_registers(CPUState *env); + +int kvm_arch_put_registers(CPUState *env); + +int kvm_arch_init(KVMState *s, int smp_cpus); + +int kvm_arch_init_vcpu(CPUState *env); + +void kvm_arch_reset_vcpu(CPUState *env); + +struct kvm_guest_debug; +struct kvm_debug_exit_arch; + +struct kvm_sw_breakpoint { + target_ulong pc; + target_ulong saved_insn; + int use_count; + QTAILQ_ENTRY(kvm_sw_breakpoint) entry; +}; + +QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); + +int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info); + +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, + target_ulong pc); + +int kvm_sw_breakpoints_active(CPUState *env); + +int kvm_arch_insert_sw_breakpoint(CPUState *current_env, + struct kvm_sw_breakpoint *bp); +int kvm_arch_remove_sw_breakpoint(CPUState *current_env, + struct kvm_sw_breakpoint *bp); +int kvm_arch_insert_hw_breakpoint(target_ulong addr, + target_ulong len, int type); +int kvm_arch_remove_hw_breakpoint(target_ulong addr, + target_ulong len, int type); +void kvm_arch_remove_all_hw_breakpoints(void); + +void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); + +int kvm_check_extension(KVMState *s, unsigned int extension); + +uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, + int reg); +void kvm_cpu_synchronize_state(CPUState *env); + +/* generic hooks - to be moved/refactored once there are more users */ + +static inline void cpu_synchronize_state(CPUState *env) +{ + if (kvm_enabled()) { + kvm_cpu_synchronize_state(env); + } +} + +#endif diff --git a/qemu/qemu-git/m68k-dis.c b/qemu/qemu-git/m68k-dis.c new file mode 100644 index 0000000..d38d5a2 --- /dev/null +++ b/qemu/qemu-git/m68k-dis.c @@ -0,0 +1,5045 @@ +/* This file is composed of several different files from the upstream + sourceware.org CVS. Original file boundaries marked with **** */ + +#include +#include +#include + +#include "dis-asm.h" + +/* **** floatformat.h from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +/*#include "ansidecl.h" */ + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +/* What is the order of the bytes. */ + +enum floatformat_byteorders { + + /* Standard little endian byte order. + EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */ + + floatformat_little, + + /* Standard big endian byte order. + EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */ + + floatformat_big, + + /* Little endian byte order but big endian word order. + EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */ + + floatformat_littlebyte_bigword + +}; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Bias added to a "true" exponent to form the biased exponent. It + is intentionally signed as, otherwize, -exp_bias can turn into a + very large number (e.g., given the exp_bias of 0x3fff and a 64 + bit long, the equation (long)(1 - exp_bias) evaluates to + 4294950914) instead of -16382). */ + int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; + + /* Internal name for debugging. */ + const char *name; + + /* Validator method. */ + int (*is_valid) (const struct floatformat *fmt, const char *from); +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformat for ARM IEEE double, little endian bytes and big endian words */ + +extern const struct floatformat floatformat_ieee_double_littlebyte_bigword; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_m88110_harris_ext; +extern const struct floatformat floatformat_arm_ext_big; +extern const struct floatformat floatformat_arm_ext_littlebyte_bigword; +/* IA-64 Floating Point register spilt into memory. */ +extern const struct floatformat floatformat_ia64_spill_big; +extern const struct floatformat floatformat_ia64_spill_little; +extern const struct floatformat floatformat_ia64_quad_big; +extern const struct floatformat floatformat_ia64_quad_little; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double (const struct floatformat *, const char *, double *); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double (const struct floatformat *, const double *, char *); + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +extern int +floatformat_is_valid (const struct floatformat *fmt, const char *from); + +#endif /* defined (FLOATFORMAT_H) */ +/* **** End of floatformat.h */ +/* **** m68k-dis.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table header for m680[01234]0/m6888[12]/m68851. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001, + 2003, 2004 Free Software Foundation, Inc. + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 1, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, + see . */ + +/* These are used as bit flags for the arch field in the m68k_opcode + structure. */ +#define _m68k_undef 0 +#define m68000 0x001 +#define m68008 m68000 /* Synonym for -m68000. otherwise unused. */ +#define m68010 0x002 +#define m68020 0x004 +#define m68030 0x008 +#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences; + gas will deal with the few differences. */ +#define m68040 0x010 +/* There is no 68050. */ +#define m68060 0x020 +#define m68881 0x040 +#define m68882 m68881 /* Synonym for -m68881. otherwise unused. */ +#define m68851 0x080 +#define cpu32 0x100 /* e.g., 68332 */ + +#define mcfmac 0x200 /* ColdFire MAC. */ +#define mcfemac 0x400 /* ColdFire EMAC. */ +#define cfloat 0x800 /* ColdFire FPU. */ +#define mcfhwdiv 0x1000 /* ColdFire hardware divide. */ + +#define mcfisa_a 0x2000 /* ColdFire ISA_A. */ +#define mcfisa_aa 0x4000 /* ColdFire ISA_A+. */ +#define mcfisa_b 0x8000 /* ColdFire ISA_B. */ +#define mcfusp 0x10000 /* ColdFire USP instructions. */ + +#define mcf5200 0x20000 +#define mcf5206e 0x40000 +#define mcf521x 0x80000 +#define mcf5249 0x100000 +#define mcf528x 0x200000 +#define mcf5307 0x400000 +#define mcf5407 0x800000 +#define mcf5470 0x1000000 +#define mcf5480 0x2000000 + + /* Handy aliases. */ +#define m68040up (m68040 | m68060) +#define m68030up (m68030 | m68040up) +#define m68020up (m68020 | m68030up) +#define m68010up (m68010 | cpu32 | m68020up) +#define m68000up (m68000 | m68010up) + +#define mfloat (m68881 | m68882 | m68040 | m68060) +#define mmmu (m68851 | m68030 | m68040 | m68060) + +/* The structure used to hold information for an opcode. */ + +struct m68k_opcode +{ + /* The opcode name. */ + const char *name; + /* The pseudo-size of the instruction(in bytes). Used to determine + number of bytes necessary to disassemble the instruction. */ + unsigned int size; + /* The opcode itself. */ + unsigned long opcode; + /* The mask used by the disassembler. */ + unsigned long match; + /* The arguments. */ + const char *args; + /* The architectures which support this opcode. */ + unsigned int arch; +}; + +/* The structure used to hold information for an opcode alias. */ + +struct m68k_opcode_alias +{ + /* The alias name. */ + const char *alias; + /* The instruction for which this is an alias. */ + const char *primary; +}; + +/* We store four bytes of opcode for all opcodes because that is the + most any of them need. The actual length of an instruction is + always at least 2 bytes, and is as much longer as necessary to hold + the operands it has. + + The match field is a mask saying which bits must match particular + opcode in order for an instruction to be an instance of that + opcode. + + The args field is a string containing two characters for each + operand of the instruction. The first specifies the kind of + operand; the second, the place it is stored. */ + +/* Kinds of operands: + Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+- + + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + a address register indirect only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + r either kind of register indirect only. Stored as 4 bits. + At the moment, used only for cas2 instruction. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + E the MAC ACC. No need to store, just as with CCR. + e the EMAC ACC[0123]. + G the MAC/EMAC MACSR. No need to store, just as with CCR. + g the EMAC ACCEXT{01,23}. + H the MASK. No need to store, just as with CCR. + i the MAC/EMAC scale factor. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 0x000 SFC Source Function Code reg [60, 40, 30, 20, 10] + 0x001 DFC Data Function Code reg [60, 40, 30, 20, 10] + 0x002 CACR Cache Control Register [60, 40, 30, 20, mcf] + 0x003 TC MMU Translation Control [60, 40] + 0x004 ITT0 Instruction Transparent + Translation reg 0 [60, 40] + 0x005 ITT1 Instruction Transparent + Translation reg 1 [60, 40] + 0x006 DTT0 Data Transparent + Translation reg 0 [60, 40] + 0x007 DTT1 Data Transparent + Translation reg 1 [60, 40] + 0x008 BUSCR Bus Control Register [60] + 0x800 USP User Stack Pointer [60, 40, 30, 20, 10] + 0x801 VBR Vector Base reg [60, 40, 30, 20, 10, mcf] + 0x802 CAAR Cache Address Register [ 30, 20] + 0x803 MSP Master Stack Pointer [ 40, 30, 20] + 0x804 ISP Interrupt Stack Pointer [ 40, 30, 20] + 0x805 MMUSR MMU Status reg [ 40] + 0x806 URP User Root Pointer [60, 40] + 0x807 SRP Supervisor Root Pointer [60, 40] + 0x808 PCR Processor Configuration reg [60] + 0xC00 ROMBAR ROM Base Address Register [520X] + 0xC04 RAMBAR0 RAM Base Address Register 0 [520X] + 0xC05 RAMBAR1 RAM Base Address Register 0 [520X] + 0xC0F MBAR0 RAM Base Address Register 0 [520X] + 0xC04 FLASHBAR FLASH Base Address Register [mcf528x] + 0xC05 RAMBAR Static RAM Base Address Register [mcf528x] + + L Register list of the type d0-d7/a0-a7 etc. + (New! Improved! Can also hold fp0-fp7, as well!) + The assembler tries to see if the registers match the insn by + looking at where the insn wants them stored. + + l Register list like L, but with all the bits reversed. + Used for going the other way. . . + + c cache identifier which may be "nc" for no cache, "ic" + for instruction cache, "dc" for data cache, or "bc" + for both caches. Used in cinv and cpush. Always + stored in position "d". + + u Any register, with ``upper'' or ``lower'' specification. Used + in the mac instructions with size word. + + The remainder are all stored as 6 bits using an address mode and a + register number; they differ in which addressing modes they match. + + * all (modes 0-6,7.0-4) + ~ alterable memory (modes 2-6,7.0,7.1) + (not 0,1,7.2-4) + % alterable (modes 0-6,7.0,7.1) + (not 7.2-4) + ; data (modes 0,2-6,7.0-4) + (not 1) + @ data, but not immediate (modes 0,2-6,7.0-3) + (not 1,7.4) + ! control (modes 2,5,6,7.0-3) + (not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1) + (not 0,1,3,4,7.2-4) + $ alterable data (modes 0,2-6,7.0,7.1) + (not 1,7.2-4) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1) + (not 1,3,4,7.2-4) + / control, or data register (modes 0,2,5,6,7.0-3) + (not 1,3,4,7.4) + > *save operands (modes 2,4,5,6,7.0,7.1) + (not 0,1,3,7.2-4) + < *restore operands (modes 2,3,5,6,7.0-3) + (not 0,1,4,7.4) + + coldfire move operands: + m (modes 0-4) + n (modes 5,7.2) + o (modes 6,7.0,7.1,7.3,7.4) + p (modes 0-5) + + coldfire bset/bclr/btst/mulsl/mulul operands: + q (modes 0,2-5) + v (modes 0,2-5,7.0,7.1) + b (modes 0,2-5,7.2) + w (modes 2-5,7.2) + y (modes 2,5) + z (modes 2,5,7.2) + x mov3q immediate operand. + 4 (modes 2,3,4,5) + */ + +/* For the 68851: */ +/* I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + 0 32 bit pmmu register + Possible values: + 000 TC Translation Control Register (68030, 68851) + + 1 16 bit pmmu register + 111 AC Access Control (68851) + + 2 8 bit pmmu register + 100 CAL Current Access Level (68851) + 101 VAL Validate Access Level (68851) + 110 SCC Stack Change Control (68851) + + 3 68030-only pmmu registers (32 bit) + 010 TT0 Transparent Translation reg 0 + (aka Access Control reg 0 -- AC0 -- on 68ec030) + 011 TT1 Transparent Translation reg 1 + (aka Access Control reg 1 -- AC1 -- on 68ec030) + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer (68851) + 010 SRP Supervisor Root Pointer (68030, 68851) + 011 CRP Cpu Root Pointer (68030, 68851) + + f function code register (68030, 68851) + 0 SFC + 1 DFC + + V VAL register only (68851) + + X BADx, BACx (16 bit) + 100 BAD Breakpoint Acknowledge Data (68851) + 101 BAC Breakpoint Acknowledge Control (68851) + + Y PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030) + Z PCSR (68851) + + | memory (modes 2-6, 7.*) + + t address test level (68030 only) + Stored as 3 bits, range 0-7. + Also used for breakpoint instruction now. + +*/ + +/* Places to put an operand, for non-general operands: + Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/ + + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + 9 second word, shifted 5 + D store in both place 1 and place 3; for divul and divsl. + B first word, low byte, for branch displacements + W second word (entire), for branch displacements + L second and third words (entire), for branch displacements + (also overloaded for move16) + b second word, low byte + w second word (entire) [variable word/long branch offset for dbra] + W second word (entire) (must be signed 16 bit value) + l second and third word (entire) + g variable branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + m For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word + and remaining 3 bits of register shifted 9 bits in first word. + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + n `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split + with MSB shifted 6 bits in first word and remaining 3 bits of + register shifted 9 bits in first word. No upper/lower + indication is done.) Use with `R' or `u' format. + o For M[S]ACw; 4 bits shifted 12 in second word (like `1'). + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + M For M[S]ACw; 4 bits in low bits of first word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + N For M[S]ACw; 4 bits in low bits of second word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + h shift indicator (scale factor), 1 bit shifted 10 in second word + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes + G EMAC accumulator, load (bit 4 2nd word, !bit8 first word) + H EMAC accumulator, non load (bit 4 2nd word, bit 8 first word) + F EMAC ACCx + f EMAC ACCy + I MAC/EMAC scale factor + / Like 's', but set 2nd word, bit 5 if trailing_ampersand set + ] first word, bit 10 +*/ + +extern const struct m68k_opcode m68k_opcodes[]; +extern const struct m68k_opcode_alias m68k_opcode_aliases[]; + +extern const int m68k_numopcodes, m68k_numaliases; + +/* **** End of m68k-opcode.h */ +/* **** m68k-dis.c from sourceware.org CVS 2005-08-14. */ +/* Print Motorola 68k instructions. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Local function prototypes. */ + +static const char * const fpcr_names[] = +{ + "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr", + "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr" +}; + +static const char *const reg_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", + "%ps", "%pc" +}; + +/* Name of register halves for MAC/EMAC. + Separate from reg_names since 'spu', 'fpl' look weird. */ +static const char *const reg_half_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%ps", "%pc" +}; + +/* Sign-extend an (unsigned char). */ +#if __STDC__ == 1 +#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch)) +#else +#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128) +#endif + +/* Get a 1 byte signed integer. */ +#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1])) + +/* Get a 2 byte signed integer. */ +#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000)) +#define NEXTWORD(p) \ + (p += 2, FETCH_DATA (info, p), \ + COERCE16 ((p[-2] << 8) + p[-1])) + +/* Get a 4 byte signed integer. */ +#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000) +#define NEXTLONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))) + +/* Get a 4 byte unsigned integer. */ +#define NEXTULONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) + +/* Get a single precision float. */ +#define NEXTSINGLE(val, p) \ + (p += 4, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val)) + +/* Get a double precision float. */ +#define NEXTDOUBLE(val, p) \ + (p += 8, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val)) + +/* Get an extended precision float. */ +#define NEXTEXTEND(val, p) \ + (p += 12, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val)) + +/* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ +#define NEXTPACKED(p) \ + (p += 12, FETCH_DATA (info, p), 0.0) + +/* Maximum length of an instruction. */ +#define MAXLEN 22 + +#include + +struct private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct private *priv = (struct private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +/* This function is used to print to the bit-bucket. */ +static int +dummy_printer (FILE *file ATTRIBUTE_UNUSED, + const char *format ATTRIBUTE_UNUSED, + ...) +{ + return 0; +} + +static void +dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED, + struct disassemble_info *info ATTRIBUTE_UNUSED) +{ +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (unsigned char *buffer, + int code, + int bits, + disassemble_info *info) +{ + int val = 0; + + switch (code) + { + case '/': /* MAC/EMAC mask bit. */ + val = buffer[3] >> 5; + break; + + case 'G': /* EMAC ACC load. */ + val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1); + break; + + case 'H': /* EMAC ACC !load. */ + val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1); + break; + + case ']': /* EMAC ACCEXT bit. */ + val = buffer[0] >> 2; + break; + + case 'I': /* MAC/EMAC scale factor. */ + val = buffer[2] >> 1; + break; + + case 'F': /* EMAC ACCx. */ + val = buffer[0] >> 1; + break; + + case 'f': + val = buffer[1]; + break; + + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + FETCH_DATA (info, buffer + 3); + val = (buffer[3] >> 4); + break; + + case 'C': + FETCH_DATA (info, buffer + 3); + val = buffer[3]; + break; + + case '1': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + case '9': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 5; + break; + + case 'e': + val = (buffer[1] >> 6); + break; + + case 'm': + val = (buffer[1] & 0x40 ? 0x8 : 0) + | ((buffer[0] >> 1) & 0x7) + | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'n': + val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7); + break; + + case 'o': + val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'M': + val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'N': + val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'h': + val = buffer[2] >> 2; + break; + + default: + abort (); + } + + switch (bits) + { + case 1: + return val & 1; + case 2: + return val & 3; + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Check if an EA is valid for a particular code. This is required + for the EMAC instructions since the type of source address determines + if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it + is a non-load EMAC instruction and the bits mean register Ry. + A similar case exists for the movem instructions where the register + mask is interpreted differently for different EAs. */ + +static bfd_boolean +m68k_valid_ea (char code, int val) +{ + int mode, mask; +#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \ + (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \ + | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11) + + switch (code) + { + case '*': + mask = M (1,1,1,1,1,1,1,1,1,1,1,1); + break; + case '~': + mask = M (0,0,1,1,1,1,1,1,1,0,0,0); + break; + case '%': + mask = M (1,1,1,1,1,1,1,1,1,0,0,0); + break; + case ';': + mask = M (1,0,1,1,1,1,1,1,1,1,1,1); + break; + case '@': + mask = M (1,0,1,1,1,1,1,1,1,1,1,0); + break; + case '!': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '&': + mask = M (0,0,1,0,0,1,1,1,1,0,0,0); + break; + case '$': + mask = M (1,0,1,1,1,1,1,1,1,0,0,0); + break; + case '?': + mask = M (1,0,1,0,0,1,1,1,1,0,0,0); + break; + case '/': + mask = M (1,0,1,0,0,1,1,1,1,1,1,0); + break; + case '|': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '>': + mask = M (0,0,1,0,1,1,1,1,1,0,0,0); + break; + case '<': + mask = M (0,0,1,1,0,1,1,1,1,1,1,0); + break; + case 'm': + mask = M (1,1,1,1,1,0,0,0,0,0,0,0); + break; + case 'n': + mask = M (0,0,0,0,0,1,0,0,0,1,0,0); + break; + case 'o': + mask = M (0,0,0,0,0,0,1,1,1,0,1,1); + break; + case 'p': + mask = M (1,1,1,1,1,1,0,0,0,0,0,0); + break; + case 'q': + mask = M (1,0,1,1,1,1,0,0,0,0,0,0); + break; + case 'v': + mask = M (1,0,1,1,1,1,0,1,1,0,0,0); + break; + case 'b': + mask = M (1,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'w': + mask = M (0,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'y': + mask = M (0,0,1,0,0,1,0,0,0,0,0,0); + break; + case 'z': + mask = M (0,0,1,0,0,1,0,0,0,1,0,0); + break; + case '4': + mask = M (0,0,1,1,1,1,0,0,0,0,0,0); + break; + default: + abort (); + } +#undef M + + mode = (val >> 3) & 7; + if (mode == 7) + mode += val & 7; + return (mask & (1 << mode)) != 0; +} + +/* Print a base register REGNO and displacement DISP, on INFO->STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (int regno, bfd_vma disp, disassemble_info *info) +{ + if (regno == -1) + { + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (disp, info); + } + else + { + char buf[50]; + + if (regno == -2) + (*info->fprintf_func) (info->stream, "@("); + else if (regno == -3) + (*info->fprintf_func) (info->stream, "%%zpc@("); + else + (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]); + + sprintf_vma (buf, disp); + (*info->fprintf_func) (info->stream, "%s", buf); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (int basereg, + unsigned char *p, + bfd_vma addr, + disassemble_info *info) +{ + int word; + static const char *const scales[] = { "", ":2", ":4", ":8" }; + bfd_vma base_disp; + bfd_vma outer_disp; + char buf[40]; + char vmabuf[50]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "%s:%c%s", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + base_disp = word & 0xff; + if ((base_disp & 0x80) != 0) + base_disp -= 0x100; + if (basereg == -1) + base_disp += addr; + print_base (basereg, base_disp, info); + (*info->fprintf_func) (info->stream, ",%s)", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + if (word & 0200) + { + if (basereg == -1) + basereg = -3; + else + basereg = -2; + } + if (word & 0100) + buf[0] = '\0'; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect). */ + if ((word & 7) == 0) + { + print_base (basereg, base_disp, info); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + print_base (basereg, base_disp, info); + if ((word & 4) == 0 && buf[0] != '\0') + { + (*info->fprintf_func) (info->stream, ",%s", buf); + buf[0] = '\0'; + } + sprintf_vma (vmabuf, outer_disp); + (*info->fprintf_func) (info->stream, ")@(%s", vmabuf); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + + return p; +} + +/* Returns number of bytes "eaten" by the operand, or + return -1 if an invalid operand was found, or -2 if + an opcode tabe error was found. + ADDR is the pc for this arg to be relative to. */ + +static int +print_insn_arg (const char *d, + unsigned char *buffer, + unsigned char *p0, + bfd_vma addr, + disassemble_info *info) +{ + int val = 0; + int place = d[1]; + unsigned char *p = p0; + int regno; + const char *regname; + unsigned char *p1; + double flval; + int flt_p; + bfd_signed_vma disp; + unsigned int uval; + + switch (*d) + { + case 'c': /* Cache identifier. */ + { + static const char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; + val = fetch_arg (buffer, place, 2, info); + (*info->fprintf_func) (info->stream, cacheFieldName[val]); + break; + } + + case 'a': /* Address register indirect only. Cf. case '+'. */ + { + (*info->fprintf_func) + (info->stream, + "%s@", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + } + + case '_': /* 32-bit absolute address for move16. */ + { + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + } + + case 'C': + (*info->fprintf_func) (info->stream, "%%ccr"); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%%sr"); + break; + + case 'U': + (*info->fprintf_func) (info->stream, "%%usp"); + break; + + case 'E': + (*info->fprintf_func) (info->stream, "%%acc"); + break; + + case 'G': + (*info->fprintf_func) (info->stream, "%%macsr"); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%%mask"); + break; + + case 'J': + { + /* FIXME: There's a problem here, different m68k processors call the + same address different names. This table can't get it right + because it doesn't know which processor it's disassembling for. */ + static const struct { const char *name; int value; } names[] + = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002}, + {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005}, + {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008}, + {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802}, + {"%msp", 0x803}, {"%isp", 0x804}, + {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */ + + /* Should we be calling this psr like we do in case 'Y'? */ + {"%mmusr",0x805}, + + {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}}; + + val = fetch_arg (buffer, place, 12, info); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + (*info->fprintf_func) (info->stream, "%s", names[regno].name); + break; + } + if (regno < 0) + (*info->fprintf_func) (info->stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3, info); + /* 0 means 8, except for the bkpt instruction... */ + if (val == 0 && d[1] != 's') + val = 8; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'x': + val = fetch_arg (buffer, place, 3, info); + /* 0 means -1. */ + if (val == 0) + val = -1; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'M': + if (place == 'h') + { + static const char *const scalefactor_name[] = { "<<", ">>" }; + val = fetch_arg (buffer, place, 1, info); + (*info->fprintf_func) (info->stream, scalefactor_name[val]); + } + else + { + val = fetch_arg (buffer, place, 8, info); + if (val & 0x80) + val = val - 0x100; + (*info->fprintf_func) (info->stream, "#%d", val); + } + break; + + case 'T': + val = fetch_arg (buffer, place, 4, info); + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'A': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info) + 010]); + break; + + case 'R': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 4, info)]); + break; + + case 'r': + regno = fetch_arg (buffer, place, 4, info); + if (regno > 7) + (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]); + else + (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]); + break; + + case 'F': + (*info->fprintf_func) + (info->stream, "%%fp%d", + fetch_arg (buffer, place, 3, info)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6, info); + if (val & 0x20) + (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]); + else + (*info->fprintf_func) (info->stream, "%d", val); + break; + + case '+': + (*info->fprintf_func) + (info->stream, "%s@+", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case '-': + (*info->fprintf_func) + (info->stream, "%s@-", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case 'k': + if (place == 'k') + (*info->fprintf_func) + (info->stream, "{%s}", + reg_names[fetch_arg (buffer, place, 3, info)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7, info); + if (val > 63) /* This is a signed constant. */ + val -= 128; + (*info->fprintf_func) (info->stream, "{#%d}", val); + } + else + return -2; + break; + + case '#': + case '^': + p1 = buffer + (*d == '#' ? 2 : 4); + if (place == 's') + val = fetch_arg (buffer, place, 4, info); + else if (place == 'C') + val = fetch_arg (buffer, place, 7, info); + else if (place == '8') + val = fetch_arg (buffer, place, 3, info); + else if (place == '3') + val = fetch_arg (buffer, place, 8, info); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w' || place == 'W') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + return -2; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + disp = NEXTBYTE (p); + else if (place == 'B') + disp = COERCE_SIGNED_CHAR (buffer[1]); + else if (place == 'w' || place == 'W') + disp = NEXTWORD (p); + else if (place == 'l' || place == 'L' || place == 'C') + disp = NEXTLONG (p); + else if (place == 'g') + { + disp = NEXTBYTE (buffer); + if (disp == 0) + disp = NEXTWORD (p); + else if (disp == -1) + disp = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset. */ + disp = NEXTLONG (p); + else + disp = NEXTWORD (p); + } + else + return -2; + + (*info->print_address_func) (addr + disp, info); + break; + + case 'd': + val = NEXTWORD (p); + (*info->fprintf_func) + (info->stream, "%s@(%d)", + reg_names[fetch_arg (buffer, place, 3, info) + 8], val); + break; + + case 's': + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'e': + val = fetch_arg(buffer, place, 2, info); + (*info->fprintf_func) (info->stream, "%%acc%d", val); + break; + + case 'g': + val = fetch_arg(buffer, place, 1, info); + (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23"); + break; + + case 'i': + val = fetch_arg(buffer, place, 2, info); + if (val == 1) + (*info->fprintf_func) (info->stream, "<<"); + else if (val == 3) + (*info->fprintf_func) (info->stream, ">>"); + else + return -1; + break; + + case 'I': + /* Get coprocessor ID... */ + val = fetch_arg (buffer, 'd', 3, info); + + if (val != 1) /* Unusual coprocessor ID? */ + (*info->fprintf_func) (info->stream, "(cpid=%d) ", val); + break; + + case '4': + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '$': + case '?': + case '/': + case '&': + case '|': + case '<': + case '>': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'v': + case 'b': + case 'w': + case 'y': + case 'z': + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6, info); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6, info); + + /* If the is invalid for *d, then reject this match. */ + if (!m68k_valid_ea (*d, val)) + return -1; + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + (*info->fprintf_func) (info->stream, "%s", reg_names[val]); + break; + + case 1: + (*info->fprintf_func) (info->stream, "%s", regname); + break; + + case 2: + (*info->fprintf_func) (info->stream, "%s@", regname); + break; + + case 3: + (*info->fprintf_func) (info->stream, "%s@+", regname); + break; + + case 4: + (*info->fprintf_func) (info->stream, "%s@-", regname); + break; + + case 5: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val); + break; + + case 6: + p = print_indexed (regno, p, addr, info); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + (*info->print_address_func) (val, info); + break; + + case 1: + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + + case 2: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (addr + val, info); + (*info->fprintf_func) (info->stream, ")"); + break; + + case 3: + p = print_indexed (-1, p, addr, info); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch (place) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + NEXTSINGLE (flval, p); + break; + + case 'F': + NEXTDOUBLE (flval, p); + break; + + case 'x': + NEXTEXTEND (flval, p); + break; + + case 'p': + flval = NEXTPACKED (p); + break; + + default: + return -1; + } + if (flt_p) /* Print a float? */ + (*info->fprintf_func) (info->stream, "#%g", flval); + else + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + default: + return -1; + } + } + + /* If place is '/', then this is the case of the mask bit for + mac/emac loads. Now that the arg has been printed, grab the + mask bit and if set, add a '&' to the arg. */ + if (place == '/') + { + val = fetch_arg (buffer, place, 1, info); + if (val) + info->fprintf_func (info->stream, "&"); + } + break; + + case 'L': + case 'l': + if (place == 'w') + { + char doneany; + p1 = buffer + 2; + val = NEXTWORD (p1); + /* Move the pointer ahead if this point is farther ahead + than the last. */ + p = p1 > p ? p1 : p; + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 16; ++regno) + if (val & (0x8000 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xffff; + doneany = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (1 << regno)) + { + int first_regno; + + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%s", reg_names[regno]); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%s", + reg_names[regno]); + } + } + else if (place == '3') + { + /* `fmovem' insn. */ + char doneany; + val = fetch_arg (buffer, place, 8, info); + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 8; ++regno) + if (val & (0x80 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xff; + doneany = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%%fp%d", regno); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%%fp%d", regno); + } + } + else if (place == '8') + { + /* fmoveml for FP status registers. */ + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, + info)]); + } + else + return -2; + break; + + case 'X': + place = '8'; + case 'Y': + case 'Z': + case 'W': + case '0': + case '1': + case '2': + case '3': + { + int val = fetch_arg (buffer, place, 5, info); + const char *name = 0; + + switch (val) + { + case 2: name = "%tt0"; break; + case 3: name = "%tt1"; break; + case 0x10: name = "%tc"; break; + case 0x11: name = "%drp"; break; + case 0x12: name = "%srp"; break; + case 0x13: name = "%crp"; break; + case 0x14: name = "%cal"; break; + case 0x15: name = "%val"; break; + case 0x16: name = "%scc"; break; + case 0x17: name = "%ac"; break; + case 0x18: name = "%psr"; break; + case 0x19: name = "%pcsr"; break; + case 0x1c: + case 0x1d: + { + int break_reg = ((buffer[3] >> 2) & 7); + + (*info->fprintf_func) + (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d", + break_reg); + } + break; + default: + (*info->fprintf_func) (info->stream, "", val); + } + if (name) + (*info->fprintf_func) (info->stream, "%s", name); + } + break; + + case 'f': + { + int fc = fetch_arg (buffer, place, 5, info); + + if (fc == 1) + (*info->fprintf_func) (info->stream, "%%dfc"); + else if (fc == 0) + (*info->fprintf_func) (info->stream, "%%sfc"); + else + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, _(""), fc); + } + break; + + case 'V': + (*info->fprintf_func) (info->stream, "%%val"); + break; + + case 't': + { + int level = fetch_arg (buffer, place, 3, info); + + (*info->fprintf_func) (info->stream, "%d", level); + } + break; + + case 'u': + { + short is_upper = 0; + int reg = fetch_arg (buffer, place, 5, info); + + if (reg & 0x10) + { + is_upper = 1; + reg &= 0xf; + } + (*info->fprintf_func) (info->stream, "%s%s", + reg_half_names[reg], + is_upper ? "u" : "l"); + } + break; + + default: + return -2; + } + + return p - p0; +} + +/* Try to match the current instruction to best and if so, return the + number of bytes consumed from the instruction stream, else zero. */ + +static int +match_insn_m68k (bfd_vma memaddr, + disassemble_info * info, + const struct m68k_opcode * best, + struct private * priv) +{ + unsigned char *save_p; + unsigned char *p; + const char *d; + + bfd_byte *buffer = priv->the_buffer; + fprintf_ftype save_printer = info->fprintf_func; + void (* save_print_address) (bfd_vma, struct disassemble_info *) + = info->print_address_func; + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Figure out how long the fixed-size portion of the instruction is. + The only place this is stored in the opcode table is + in the arguments--look for arguments which specify fields in the 2nd + or 3rd words of the instruction. */ + for (d = best->args; *d; d += 2) + { + /* I don't think it is necessary to be checking d[0] here; + I suspect all this could be moved to the case statement below. */ + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8') + p = buffer + 4; + } + + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) + p = buffer + 4; + + switch (d[1]) + { + case '1': + case '2': + case '3': + case '7': + case '8': + case '9': + case 'i': + if (p - buffer < 4) + p = buffer + 4; + break; + case '4': + case '5': + case '6': + if (p - buffer < 6) + p = buffer + 6; + break; + default: + break; + } + } + + /* pflusha is an exceptions. It takes no arguments but is two words + long. Recognize it by looking at the lower 16 bits of the mask. */ + if (p - buffer < 4 && (best->match & 0xFFFF) != 0) + p = buffer + 4; + + /* lpstop is another exception. It takes a one word argument but is + three words long. */ + if (p - buffer < 6 + && (best->match & 0xffff) == 0xffff + && best->args[0] == '#' + && best->args[1] == 'w') + { + /* Copy the one word argument into the usual location for a one + word argument, to simplify printing it. We can get away with + this because we know exactly what the second word is, and we + aren't going to print anything based on it. */ + p = buffer + 6; + FETCH_DATA (info, p); + buffer[2] = buffer[4]; + buffer[3] = buffer[5]; + } + + FETCH_DATA (info, p); + + d = best->args; + + save_p = p; + info->print_address_func = dummy_print_address; + info->fprintf_func = (fprintf_ftype) dummy_printer; + + /* We scan the operands twice. The first time we don't print anything, + but look for errors. */ + for (; *d; d += 2) + { + int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + + if (eaten >= 0) + p += eaten; + else if (eaten == -1) + { + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 0; + } + else + { + info->fprintf_func (info->stream, + /* xgettext:c-format */ + _("\n"), + best->name, best->args); + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 2; + } + } + + p = save_p; + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + + d = best->args; + + info->fprintf_func (info->stream, "%s", best->name); + + if (*d) + info->fprintf_func (info->stream, " "); + + while (*d) + { + p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + d += 2; + + if (*d && *(d - 2) != 'I' && *d != 'k') + info->fprintf_func (info->stream, ","); + } + + return p - buffer; +} + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on INFO->STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_m68k (bfd_vma memaddr, disassemble_info *info) +{ + int i; + const char *d; + unsigned int arch_mask; + struct private priv; + bfd_byte *buffer = priv.the_buffer; + int major_opcode; + static int numopcodes[16]; + static const struct m68k_opcode **opcodes[16]; + int val; + + if (!opcodes[0]) + { + /* Speed up the matching by sorting the opcode + table on the upper four bits of the opcode. */ + const struct m68k_opcode **opc_pointer[16]; + + /* First count how many opcodes are in each of the sixteen buckets. */ + for (i = 0; i < m68k_numopcodes; i++) + numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++; + + /* Then create a sorted table of pointers + that point into the unsorted table. */ + opc_pointer[0] = malloc (sizeof (struct m68k_opcode *) + * m68k_numopcodes); + opcodes[0] = opc_pointer[0]; + + for (i = 1; i < 16; i++) + { + opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1]; + opcodes[i] = opc_pointer[i]; + } + + for (i = 0; i < m68k_numopcodes; i++) + *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i]; + } + + info->private_data = (PTR) &priv; + /* Tell objdump to use two bytes per chunk + and six bytes per line for displaying raw data. */ + info->bytes_per_chunk = 2; + info->bytes_per_line = 6; + info->display_endian = BFD_ENDIAN_BIG; + priv.max_fetched = priv.the_buffer; + priv.insn_start = memaddr; + + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + switch (info->mach) + { + default: + case 0: + arch_mask = (unsigned int) -1; + break; + case bfd_mach_m68000: + arch_mask = m68000|m68881|m68851; + break; + case bfd_mach_m68008: + arch_mask = m68008|m68881|m68851; + break; + case bfd_mach_m68010: + arch_mask = m68010|m68881|m68851; + break; + case bfd_mach_m68020: + arch_mask = m68020|m68881|m68851; + break; + case bfd_mach_m68030: + arch_mask = m68030|m68881|m68851; + break; + case bfd_mach_m68040: + arch_mask = m68040|m68881|m68851; + break; + case bfd_mach_m68060: + arch_mask = m68060|m68881|m68851; + break; + case bfd_mach_mcf5200: + arch_mask = mcfisa_a; + break; + case bfd_mach_mcf521x: + case bfd_mach_mcf528x: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac; + break; + case bfd_mach_mcf5206e: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5249: + arch_mask = mcfisa_a|mcfhwdiv|mcfemac; + break; + case bfd_mach_mcf5307: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5407: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac; + break; + case bfd_mach_mcf547x: + case bfd_mach_mcf548x: + case bfd_mach_mcfv4e: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac; + break; + } + + FETCH_DATA (info, buffer + 2); + major_opcode = (buffer[0] >> 4) & 15; + + for (i = 0; i < numopcodes[major_opcode]; i++) + { + const struct m68k_opcode *opc = opcodes[major_opcode][i]; + unsigned long opcode = opc->opcode; + unsigned long match = opc->match; + + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + /* Only fetch the next two bytes if we need to. */ + && (((0xffff & match) == 0) + || + (FETCH_DATA (info, buffer + 4) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + ) + && (opc->arch & arch_mask) != 0) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = opc->args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == '\0') + for (d = opc->args; *d; d += 2) + if (d[1] == 't') + break; + + /* Don't match fmovel with more than one register; + wait for fmoveml. */ + if (*d == '\0') + { + for (d = opc->args; *d; d += 2) + { + if (d[0] == 's' && d[1] == '8') + { + val = fetch_arg (buffer, d[1], 3, info); + if ((val & (val - 1)) != 0) + break; + } + } + } + + if (*d == '\0') + if ((val = match_insn_m68k (memaddr, info, opc, & priv))) + return val; + } + } + + /* Handle undefined instructions. */ + info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; +} +/* **** End of m68k-dis.c */ +/* **** m68k-opc.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 1, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, + see . */ + +#define one(x) ((unsigned int) (x) << 16) +#define two(x, y) (((unsigned int) (x) << 16) + (y)) + +/* The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at + runtime. */ + +const struct m68k_opcode m68k_opcodes[] = +{ +{"abcd", 2, one(0140400), one(0170770), "DsDd", m68000up }, +{"abcd", 2, one(0140410), one(0170770), "-s-d", m68000up }, + +{"addaw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addal", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"addib", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addiw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, + +{"addqb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addqw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addql", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, + +/* The add opcode can generate the adda, addi, and addq instructions. */ +{"addb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addb", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addb", 2, one(0150000), one(0170700), ";bDd", m68000up }, +{"addb", 2, one(0150400), one(0170700), "Dd~b", m68000up }, +{"addw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addw", 2, one(0150100), one(0170700), "*wDd", m68000up }, +{"addw", 2, one(0150500), one(0170700), "Dd~w", m68000up }, +{"addl", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, +{"addl", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addl", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, +{"addl", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"addl", 2, one(0150200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"addl", 2, one(0150600), one(0170700), "Dd~l", m68000up | mcfisa_a }, + +{"addxb", 2, one(0150400), one(0170770), "DsDd", m68000up }, +{"addxb", 2, one(0150410), one(0170770), "-s-d", m68000up }, +{"addxw", 2, one(0150500), one(0170770), "DsDd", m68000up }, +{"addxw", 2, one(0150510), one(0170770), "-s-d", m68000up }, +{"addxl", 2, one(0150600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"addxl", 2, one(0150610), one(0170770), "-s-d", m68000up }, + +{"andib", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andib", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andiw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andiw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andi", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andi", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andi", 4, one(0001174), one(0177777), "#wSs", m68000up }, + +/* The and opcode can generate the andi instruction. */ +{"andb", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andb", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andb", 2, one(0140000), one(0170700), ";bDd", m68000up }, +{"andb", 2, one(0140400), one(0170700), "Dd~b", m68000up }, +{"andw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andw", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"andw", 2, one(0140500), one(0170700), "Dd~w", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andl", 2, one(0140200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"andl", 2, one(0140600), one(0170700), "Dd~l", m68000up | mcfisa_a }, +{"and", 4, one(0001100), one(0177700), "#w$w", m68000up }, +{"and", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"and", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"and", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"and", 2, one(0140500), one(0170700), "Dd~w", m68000up }, + +{"aslb", 2, one(0160400), one(0170770), "QdDs", m68000up }, +{"aslb", 2, one(0160440), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160500), one(0170770), "QdDs", m68000up }, +{"aslw", 2, one(0160540), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160700), one(0177700), "~s", m68000up }, +{"asll", 2, one(0160600), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asll", 2, one(0160640), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"asrb", 2, one(0160000), one(0170770), "QdDs", m68000up }, +{"asrb", 2, one(0160040), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160100), one(0170770), "QdDs", m68000up }, +{"asrw", 2, one(0160140), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160300), one(0177700), "~s", m68000up }, +{"asrl", 2, one(0160200), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asrl", 2, one(0160240), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"bhiw", 2, one(0061000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blsw", 2, one(0061400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bccw", 2, one(0062000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bcsw", 2, one(0062400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bnew", 2, one(0063000), one(0177777), "BW", m68000up | mcfisa_a }, +{"beqw", 2, one(0063400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvcw", 2, one(0064000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvsw", 2, one(0064400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bplw", 2, one(0065000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bmiw", 2, one(0065400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgew", 2, one(0066000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bltw", 2, one(0066400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgtw", 2, one(0067000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blew", 2, one(0067400), one(0177777), "BW", m68000up | mcfisa_a }, + +{"bhil", 2, one(0061377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blsl", 2, one(0061777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bccl", 2, one(0062377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bcsl", 2, one(0062777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bnel", 2, one(0063377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"beql", 2, one(0063777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvcl", 2, one(0064377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvsl", 2, one(0064777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bpll", 2, one(0065377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bmil", 2, one(0065777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgel", 2, one(0066377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bltl", 2, one(0066777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgtl", 2, one(0067377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blel", 2, one(0067777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, + +{"bhis", 2, one(0061000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blss", 2, one(0061400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bccs", 2, one(0062000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bcss", 2, one(0062400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bnes", 2, one(0063000), one(0177400), "BB", m68000up | mcfisa_a }, +{"beqs", 2, one(0063400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvcs", 2, one(0064000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvss", 2, one(0064400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bpls", 2, one(0065000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bmis", 2, one(0065400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bges", 2, one(0066000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blts", 2, one(0066400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bgts", 2, one(0067000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bles", 2, one(0067400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"jhi", 2, one(0061000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jls", 2, one(0061400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcc", 2, one(0062000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcs", 2, one(0062400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jne", 2, one(0063000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jeq", 2, one(0063400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvc", 2, one(0064000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvs", 2, one(0064400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jpl", 2, one(0065000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jmi", 2, one(0065400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jge", 2, one(0066000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jlt", 2, one(0066400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jgt", 2, one(0067000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jle", 2, one(0067400), one(0177400), "Bg", m68000up | mcfisa_a }, + +{"bchg", 2, one(0000500), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bchg", 4, one(0004100), one(0177700), "#b$s", m68000up }, +{"bchg", 4, one(0004100), one(0177700), "#bqs", mcfisa_a }, + +{"bclr", 2, one(0000600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bclr", 4, one(0004200), one(0177700), "#b$s", m68000up }, +{"bclr", 4, one(0004200), one(0177700), "#bqs", mcfisa_a }, + +{"bfchg", 4, two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfclr", 4, two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfexts", 4, two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfextu", 4, two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfffo", 4, two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfins", 4, two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up }, +{"bfset", 4, two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bftst", 4, two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up }, + +{"bgnd", 2, one(0045372), one(0177777), "", cpu32 }, + +{"bitrev", 2, one(0000300), one(0177770), "Ds", mcfisa_aa}, + +{"bkpt", 2, one(0044110), one(0177770), "ts", m68010up }, + +{"braw", 2, one(0060000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bral", 2, one(0060377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bras", 2, one(0060000), one(0177400), "BB", m68000up | mcfisa_a }, + +{"bset", 2, one(0000700), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bset", 2, one(0000700), one(0170700), "Ddvs", mcfisa_a }, +{"bset", 4, one(0004300), one(0177700), "#b$s", m68000up }, +{"bset", 4, one(0004300), one(0177700), "#bqs", mcfisa_a }, + +{"bsrw", 2, one(0060400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bsrl", 2, one(0060777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bsrs", 2, one(0060400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"btst", 2, one(0000400), one(0170700), "Dd;b", m68000up | mcfisa_a }, +{"btst", 4, one(0004000), one(0177700), "#b@s", m68000up }, +{"btst", 4, one(0004000), one(0177700), "#bqs", mcfisa_a }, + +{"byterev", 2, one(0001300), one(0177770), "Ds", mcfisa_aa}, + +{"callm", 4, one(0003300), one(0177700), "#b!s", m68020 }, + +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, + +{"casb", 4, two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casw", 4, two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casl", 4, two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, + +{"chk2b", 4, two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2w", 4, two(0001300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2l", 4, two(0002300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"chkl", 2, one(0040400), one(0170700), ";lDd", m68000up }, +{"chkw", 2, one(0040600), one(0170700), ";wDd", m68000up }, + +#define SCOPE_LINE (0x1 << 3) +#define SCOPE_PAGE (0x2 << 3) +#define SCOPE_ALL (0x3 << 3) + +{"cinva", 2, one(0xf400|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cinvl", 2, one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up }, +{"cinvp", 2, one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +{"cpusha", 2, one(0xf420|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cpushl", 2, one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a }, +{"cpushp", 2, one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +#undef SCOPE_LINE +#undef SCOPE_PAGE +#undef SCOPE_ALL + +{"clrb", 2, one(0041000), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrw", 2, one(0041100), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrl", 2, one(0041200), one(0177700), "$s", m68000up | mcfisa_a }, + +{"cmp2b", 4, two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2w", 4, two(0001300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2l", 4, two(0002300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"cmpaw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpal", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"cmpib", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpib", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpiw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpiw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpil", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpil", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, + +{"cmpmb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpmw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpml", 2, one(0130610), one(0170770), "+s+d", m68000up }, + +/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions. */ +{"cmpb", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpb", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), ";bDd", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), "*bDd", mcfisa_b }, +{"cmpw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpw", 2, one(0130100), one(0170700), "*wDd", m68000up | mcfisa_b }, +{"cmpl", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"cmpl", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpl", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, +{"cmpl", 2, one(0130610), one(0170770), "+s+d", m68000up }, +{"cmpl", 2, one(0130200), one(0170700), "*lDd", m68000up | mcfisa_a }, + +{"dbcc", 2, one(0052310), one(0177770), "DsBw", m68000up }, +{"dbcs", 2, one(0052710), one(0177770), "DsBw", m68000up }, +{"dbeq", 2, one(0053710), one(0177770), "DsBw", m68000up }, +{"dbf", 2, one(0050710), one(0177770), "DsBw", m68000up }, +{"dbge", 2, one(0056310), one(0177770), "DsBw", m68000up }, +{"dbgt", 2, one(0057310), one(0177770), "DsBw", m68000up }, +{"dbhi", 2, one(0051310), one(0177770), "DsBw", m68000up }, +{"dble", 2, one(0057710), one(0177770), "DsBw", m68000up }, +{"dbls", 2, one(0051710), one(0177770), "DsBw", m68000up }, +{"dblt", 2, one(0056710), one(0177770), "DsBw", m68000up }, +{"dbmi", 2, one(0055710), one(0177770), "DsBw", m68000up }, +{"dbne", 2, one(0053310), one(0177770), "DsBw", m68000up }, +{"dbpl", 2, one(0055310), one(0177770), "DsBw", m68000up }, +{"dbt", 2, one(0050310), one(0177770), "DsBw", m68000up }, +{"dbvc", 2, one(0054310), one(0177770), "DsBw", m68000up }, +{"dbvs", 2, one(0054710), one(0177770), "DsBw", m68000up }, + +{"divsw", 2, one(0100700), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divsl", 4, two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"divuw", 2, one(0100300), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divul", 4, two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"eorib", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorib", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eoriw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eoriw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eori", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eori", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eori", 4, one(0005100), one(0177700), "#w$s", m68000up }, + +/* The eor opcode can generate the eori instruction. */ +{"eorb", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorb", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eorb", 2, one(0130400), one(0170700), "Dd$s", m68000up }, +{"eorw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eorw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eorw", 2, one(0130500), one(0170700), "Dd$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eorl", 2, one(0130600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"eor", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eor", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eor", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up }, + +{"exg", 2, one(0140500), one(0170770), "DdDs", m68000up }, +{"exg", 2, one(0140510), one(0170770), "AdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "DdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "AsDd", m68000up }, + +{"extw", 2, one(0044200), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extl", 2, one(0044300), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extbl", 2, one(0044700), one(0177770), "Ds", m68020up|cpu32|mcfisa_a }, + +{"ff1", 2, one(0002300), one(0177770), "Ds", mcfisa_aa}, + +/* float stuff starts here */ + +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsp", 4, two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fabsx", 4, two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsp", 4, two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsabss", 4, two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabss", 4, two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdabsb", 4, two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsb", 4, two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up}, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up}, +{"fdabsl", 4, two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsl", 4, two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up}, +{"fdabsp", 4, two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up}, +{"fdabss", 4, two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabss", 4, two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up}, +{"fdabsw", 4, two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsw", 4, two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt", m68040up}, + +{"facosb", 4, two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"facosd", 4, two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"facosl", 4, two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"facosp", 4, two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"facoss", 4, two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"facosw", 4, two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"facosx", 4, two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddp", 4, two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddx", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"faddx", 4, two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddp", 4, two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddx", 4, two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsaddx", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdaddb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddb", 4, two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdaddl", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdaddl", 4, two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdaddp", 4, two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fasinb", 4, two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fasind", 4, two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fasinl", 4, two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fasinp", 4, two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fasins", 4, two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fasinw", 4, two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fasinx", 4, two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanb", 4, two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatand", 4, two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanl", 4, two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanp", 4, two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatans", 4, two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanw", 4, two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanx", 4, two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanhb", 4, two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatanhd", 4, two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanhl", 4, two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanhp", 4, two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatanhs", 4, two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanhw", 4, two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fbeq", 2, one(0xF081), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbf", 2, one(0xF080), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbge", 2, one(0xF093), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgl", 2, one(0xF096), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgle", 2, one(0xF097), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgt", 2, one(0xF092), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fble", 2, one(0xF095), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fblt", 2, one(0xF094), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbne", 2, one(0xF08E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnge", 2, one(0xF09C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngl", 2, one(0xF099), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngle", 2, one(0xF098), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngt", 2, one(0xF09D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnle", 2, one(0xF09A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnlt", 2, one(0xF09B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fboge", 2, one(0xF083), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogl", 2, one(0xF086), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogt", 2, one(0xF082), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbole", 2, one(0xF085), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbolt", 2, one(0xF084), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbor", 2, one(0xF087), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbseq", 2, one(0xF091), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsf", 2, one(0xF090), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsne", 2, one(0xF09E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbst", 2, one(0xF09F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbt", 2, one(0xF08F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbueq", 2, one(0xF089), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbuge", 2, one(0xF08B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbugt", 2, one(0xF08A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbule", 2, one(0xF08D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbult", 2, one(0xF08C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbun", 2, one(0xF088), one(0xF1FF), "IdBW", mfloat | cfloat }, + +{"fbeql", 2, one(0xF0C1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbfl", 2, one(0xF0C0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgel", 2, one(0xF0D3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgll", 2, one(0xF0D6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbglel", 2, one(0xF0D7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgtl", 2, one(0xF0D2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fblel", 2, one(0xF0D5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbltl", 2, one(0xF0D4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnel", 2, one(0xF0CE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngel", 2, one(0xF0DC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngll", 2, one(0xF0D9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnglel", 2, one(0xF0D8), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngtl", 2, one(0xF0DD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnlel", 2, one(0xF0DA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnltl", 2, one(0xF0DB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogel", 2, one(0xF0C3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogll", 2, one(0xF0C6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogtl", 2, one(0xF0C2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbolel", 2, one(0xF0C5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fboltl", 2, one(0xF0C4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fborl", 2, one(0xF0C7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbseql", 2, one(0xF0D1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsfl", 2, one(0xF0D0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsnel", 2, one(0xF0DE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbstl", 2, one(0xF0DF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbtl", 2, one(0xF0CF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbueql", 2, one(0xF0C9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugel", 2, one(0xF0CB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugtl", 2, one(0xF0CA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbulel", 2, one(0xF0CD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbultl", 2, one(0xF0CC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbunl", 2, one(0xF0C8), one(0xF1FF), "IdBC", mfloat | cfloat }, + +{"fjeq", 2, one(0xF081), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjf", 2, one(0xF080), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjge", 2, one(0xF093), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgl", 2, one(0xF096), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgle", 2, one(0xF097), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgt", 2, one(0xF092), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjle", 2, one(0xF095), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjlt", 2, one(0xF094), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjne", 2, one(0xF08E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnge", 2, one(0xF09C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngl", 2, one(0xF099), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngle", 2, one(0xF098), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngt", 2, one(0xF09D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnle", 2, one(0xF09A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnlt", 2, one(0xF09B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjoge", 2, one(0xF083), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogl", 2, one(0xF086), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogt", 2, one(0xF082), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjole", 2, one(0xF085), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjolt", 2, one(0xF084), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjor", 2, one(0xF087), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjseq", 2, one(0xF091), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsf", 2, one(0xF090), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsne", 2, one(0xF09E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjst", 2, one(0xF09F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjt", 2, one(0xF08F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjueq", 2, one(0xF089), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjuge", 2, one(0xF08B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjugt", 2, one(0xF08A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjule", 2, one(0xF08D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjult", 2, one(0xF08C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjun", 2, one(0xF088), one(0xF1BF), "IdBc", mfloat | cfloat }, + +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fcmpd", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpp", 4, two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpx", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcmpx", 4, two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fcosb", 4, two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcosd", 4, two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcosl", 4, two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcosp", 4, two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoss", 4, two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcosw", 4, two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcosx", 4, two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fcoshb", 4, two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcoshd", 4, two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcoshl", 4, two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcoshp", 4, two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoshs", 4, two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcoshw", 4, two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fdbeq", 4, two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbf", 4, two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbge", 4, two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgl", 4, two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgle", 4, two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgt", 4, two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdble", 4, two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdblt", 4, two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbne", 4, two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnge", 4, two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngl", 4, two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngle", 4, two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngt", 4, two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnle", 4, two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnlt", 4, two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdboge", 4, two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogl", 4, two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogt", 4, two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbole", 4, two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbolt", 4, two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbor", 4, two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbseq", 4, two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsf", 4, two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsne", 4, two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbst", 4, two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbt", 4, two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbueq", 4, two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbuge", 4, two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbugt", 4, two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbule", 4, two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbult", 4, two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbun", 4, two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, + +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivd", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivp", 4, two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivx", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fdivx", 4, two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivp", 4, two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivx", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsdivx", 4, two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivd", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivp", 4, two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivx", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fddivx", 4, two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fetoxb", 4, two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxd", 4, two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxl", 4, two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxp", 4, two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxs", 4, two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxw", 4, two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fetoxm1b", 4, two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxm1d", 4, two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxm1l", 4, two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxm1p", 4, two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxm1s", 4, two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxm1w", 4, two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetexpb", 4, two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetexpd", 4, two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetexpl", 4, two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetexpp", 4, two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetexps", 4, two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetexpw", 4, two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetmanb", 4, two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetmand", 4, two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetmanl", 4, two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetmanp", 4, two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetmans", 4, two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetmanw", 4, two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintp", 4, two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintx", 4, two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzp", 4, two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog10b", 4, two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog10d", 4, two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog10l", 4, two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog10p", 4, two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog10s", 4, two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog10w", 4, two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog10x", 4, two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog2b", 4, two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog2d", 4, two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog2l", 4, two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog2p", 4, two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog2s", 4, two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog2w", 4, two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog2x", 4, two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognb", 4, two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognd", 4, two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognl", 4, two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp", 4, two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flogns", 4, two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognw", 4, two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognx", 4, two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognp1b", 4, two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognp1d", 4, two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognp1l", 4, two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp1p", 4, two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flognp1s", 4, two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognp1w", 4, two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fmodb", 4, two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmodd", 4, two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmodl", 4, two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmodp", 4, two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmods", 4, two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmodw", 4, two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmodx", 4, two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmodx", 4, two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat }, +{"fmoved", 4, two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat }, +/* FIXME: the next two variants should not permit moving an address + register to anything but the floating point instruction register. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, + /* Move the FP control registers. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat }, +{"fmovep", 4, two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmovep", 4, two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat }, +{"fmovep", 4, two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovex", 4, two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat }, +{"fmovex", 4, two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fmovex", 4, two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat }, + +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoveb", 4, two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoved", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovel", 4, two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoves", 4, two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovew", 4, two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovex", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmovex", 4, two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsmovep", 4, two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoveb", 4, two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoved", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovel", 4, two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoves", 4, two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovew", 4, two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovex", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmovex", 4, two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdmovep", 4, two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fmovecrx", 4, two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, + +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat }, + +{"fmovemx", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, + +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +/* FIXME: In the next instruction, we should only permit %dn if the + target is a single register. We should only permit %an if the + target is a single %fpiar. */ +{"fmoveml", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat }, + +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat }, + +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovem", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, +{"fmovem", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat }, + +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmuld", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulp", 4, two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulx", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmulx", 4, two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulp", 4, two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulx", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmulx", 4, two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulp", 4, two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulx", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmulx", 4, two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegp", 4, two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fnegx", 4, two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegp", 4, two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegp", 4, two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fnop", 4, two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat }, + +{"fremb", 4, two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fremd", 4, two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"freml", 4, two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fremp", 4, two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"frems", 4, two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fremw", 4, two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fremx", 4, two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fremx", 4, two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"frestore", 2, one(0xF140), one(0xF1C0), "Ids", mfloat }, +{"fsave", 2, one(0xF100), one(0xF1C0), "Idzs", cfloat }, + +{"fscaleb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fscaled", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fscalel", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fscalep", 4, two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fscales", 4, two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fscalew", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fscalex", 4, two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fscalex", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +/* $ is necessary to prevent the assembler from using PC-relative. + If @ were used, "label: fseq label" could produce "ftrapeq", 2, + because "label" became "pc@label". */ +{"fseq", 4, two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsf", 4, two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsge", 4, two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgl", 4, two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgle", 4, two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgt", 4, two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsle", 4, two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fslt", 4, two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsne", 4, two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnge", 4, two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngl", 4, two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngle", 4, two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngt", 4, two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnle", 4, two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnlt", 4, two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsoge", 4, two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogl", 4, two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogt", 4, two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsole", 4, two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsolt", 4, two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsor", 4, two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsseq", 4, two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssf", 4, two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssne", 4, two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsst", 4, two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fst", 4, two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsueq", 4, two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsuge", 4, two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsugt", 4, two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsule", 4, two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsult", 4, two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsun", 4, two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, + +{"fsgldivb", 4, two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsgldivd", 4, two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsgldivl", 4, two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsgldivp", 4, two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsgldivs", 4, two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsgldivw", 4, two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsglmulb", 4, two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsglmuld", 4, two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsglmull", 4, two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsglmulp", 4, two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsglmuls", 4, two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsglmulw", 4, two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsinb", 4, two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsind", 4, two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinl", 4, two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinp", 4, two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsins", 4, two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinw", 4, two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinx", 4, two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsincosb", 4, two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat }, +{"fsincosd", 4, two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat }, +{"fsincosl", 4, two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat }, +{"fsincosp", 4, two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat }, +{"fsincoss", 4, two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat }, +{"fsincosw", 4, two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat }, + +{"fsinhb", 4, two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsinhd", 4, two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinhl", 4, two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinhp", 4, two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsinhs", 4, two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinhw", 4, two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtp", 4, two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtp", 4, two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtp", 4, two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubd", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubp", 4, two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsubx", 4, two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubb", 4, two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubp", 4, two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssubx", 4, two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsubb", 4, two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubb", 4, two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsubd", 4, two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsubl", 4, two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubl", 4, two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsubp", 4, two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsubs", 4, two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubs", 4, two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsubw", 4, two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubw", 4, two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"ftanb", 4, two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftand", 4, two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanl", 4, two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanp", 4, two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftans", 4, two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanw", 4, two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanx", 4, two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftanhb", 4, two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftanhd", 4, two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanhl", 4, two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanhp", 4, two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftanhs", 4, two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanhw", 4, two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftentoxb", 4, two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftentoxd", 4, two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftentoxl", 4, two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftentoxp", 4, two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftentoxs", 4, two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftentoxw", 4, two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftrapeq", 4, two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapf", 4, two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapge", 4, two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgl", 4, two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgle", 4, two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgt", 4, two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraple", 4, two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraplt", 4, two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapne", 4, two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnge", 4, two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngl", 4, two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngt", 4, two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnle", 4, two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnlt", 4, two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapoge", 4, two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogl", 4, two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogt", 4, two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapole", 4, two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapolt", 4, two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapor", 4, two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapseq", 4, two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsf", 4, two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsne", 4, two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapst", 4, two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapt", 4, two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapueq", 4, two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapuge", 4, two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapugt", 4, two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapule", 4, two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapult", 4, two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapun", 4, two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat }, + +{"ftrapeqw", 4, two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapfw", 4, two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgew", 4, two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglw", 4, two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgtw", 4, two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraplew", 4, two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapltw", 4, two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnew", 4, two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraporw", 4, two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsfw", 4, two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapstw", 4, two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraptw", 4, two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapunw", 4, two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, + +{"ftrapeql", 4, two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapfl", 4, two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgel", 4, two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgll", 4, two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgtl", 4, two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraplel", 4, two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapltl", 4, two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnel", 4, two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraporl", 4, two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsfl", 4, two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapstl", 4, two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraptl", 4, two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapunl", 4, two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, + +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat }, +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstd", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstp", 4, two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstx", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat }, +{"ftstx", 4, two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat }, + +{"ftwotoxb", 4, two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftwotoxd", 4, two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftwotoxl", 4, two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftwotoxp", 4, two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftwotoxs", 4, two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftwotoxw", 4, two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"halt", 2, one(0045310), one(0177777), "", m68060 | mcfisa_a }, + +{"illegal", 2, one(0045374), one(0177777), "", m68000up | mcfisa_a }, +{"intouch", 2, one(0xf428), one(0xfff8), "As", mcfisa_b }, + +{"jmp", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jra", 2, one(0060000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jra", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jbsr", 2, one(0060400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jbsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"lea", 2, one(0040700), one(0170700), "!sAd", m68000up | mcfisa_a }, + +{"lpstop", 6, two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 }, + +{"linkw", 4, one(0047120), one(0177770), "As#w", m68000up | mcfisa_a }, +{"linkl", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, +{"link", 4, one(0047120), one(0177770), "As#W", m68000up | mcfisa_a }, +{"link", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, + +{"lslb", 2, one(0160410), one(0170770), "QdDs", m68000up }, +{"lslb", 2, one(0160450), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0160510), one(0170770), "QdDs", m68000up }, +{"lslw", 2, one(0160550), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0161700), one(0177700), "~s", m68000up }, +{"lsll", 2, one(0160610), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsll", 2, one(0160650), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"lsrb", 2, one(0160010), one(0170770), "QdDs", m68000up }, +{"lsrb", 2, one(0160050), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0160110), one(0170770), "QdDs", m68000up }, +{"lsrw", 2, one(0160150), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0161300), one(0177700), "~s", m68000up }, +{"lsrl", 2, one(0160210), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsrl", 2, one(0160250), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac }, +{"macw", 4, two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac }, + +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +/* NOTE: The mcf5200 family programmer's reference manual does not + indicate the byte form of the movea instruction is invalid (as it + is on 68000 family cpus). However, experiments on the 5202 yeild + unexpected results. The value is copied, but it is not sign extended + (as is done with movea.w) and the top three bytes in the address + register are not disturbed. I don't know if this is the intended + behavior --- it could be a hole in instruction decoding (Motorola + decided not to trap all invalid instructions for performance reasons) + --- but I suspect that it is not. + + I reported this to Motorola ISD Technical Communications Support, + which replied that other coldfire assemblers reject movea.b. For + this reason I've decided to not allow moveab. + + jtc@cygnus.com - 97/01/24. */ + +{"moveal", 2, one(0020100), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"moveaw", 2, one(0030100), one(0170700), "*wAd", m68000up | mcfisa_a }, + +{"movclrl", 2, one(0xA1C0), one(0xf9f0), "eFRs", mcfemac }, + +{"movec", 4, one(0047173), one(0177777), "R1Jj", m68010up | mcfisa_a }, +{"movec", 4, one(0047173), one(0177777), "R1#j", m68010up | mcfisa_a }, +{"movec", 4, one(0047172), one(0177777), "JjR1", m68010up }, +{"movec", 4, one(0047172), one(0177777), "#jR1", m68010up }, + +{"movemw", 4, one(0044200), one(0177700), "Lw&s", m68000up }, +{"movemw", 4, one(0044240), one(0177770), "lw-s", m68000up }, +{"movemw", 4, one(0044200), one(0177700), "#w>s", m68000up }, +{"movemw", 4, one(0046200), one(0177700), "s", m68000up }, +{"moveml", 4, one(0046300), one(0177700), ",accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +{"mulsw", 2, one(0140700), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulsl", 4, two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"muluw", 2, one(0140300), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulul", 4, two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"nbcd", 2, one(0044000), one(0177700), "$s", m68000up }, + +{"negb", 2, one(0042000), one(0177700), "$s", m68000up }, +{"negw", 2, one(0042100), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "Ds", mcfisa_a}, + +{"negxb", 2, one(0040000), one(0177700), "$s", m68000up }, +{"negxw", 2, one(0040100), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "Ds", mcfisa_a}, + +{"nop", 2, one(0047161), one(0177777), "", m68000up | mcfisa_a}, + +{"notb", 2, one(0043000), one(0177700), "$s", m68000up }, +{"notw", 2, one(0043100), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "Ds", mcfisa_a}, + +{"orib", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orib", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"oriw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"oriw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"ori", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"ori", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"ori", 4, one(0000174), one(0177777), "#wSs", m68000up }, + +/* The or opcode can generate the ori instruction. */ +{"orb", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orb", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"orb", 2, one(0100000), one(0170700), ";bDd", m68000up }, +{"orb", 2, one(0100400), one(0170700), "Dd~s", m68000up }, +{"orw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"orw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"orw", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"orw", 2, one(0100500), one(0170700), "Dd~s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"orl", 2, one(0100200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"orl", 2, one(0100600), one(0170700), "Dd~s", m68000up | mcfisa_a }, +{"or", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"or", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"or", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"or", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"or", 2, one(0100500), one(0170700), "Dd~s", m68000up }, + +{"pack", 4, one(0100500), one(0170770), "DsDd#w", m68020up }, +{"pack", 4, one(0100510), one(0170770), "-s-d#w", m68020up }, + +{"pbac", 2, one(0xf087), one(0xffbf), "Bc", m68851 }, +{"pbacw", 2, one(0xf087), one(0xffff), "BW", m68851 }, +{"pbas", 2, one(0xf086), one(0xffbf), "Bc", m68851 }, +{"pbasw", 2, one(0xf086), one(0xffff), "BW", m68851 }, +{"pbbc", 2, one(0xf081), one(0xffbf), "Bc", m68851 }, +{"pbbcw", 2, one(0xf081), one(0xffff), "BW", m68851 }, +{"pbbs", 2, one(0xf080), one(0xffbf), "Bc", m68851 }, +{"pbbsw", 2, one(0xf080), one(0xffff), "BW", m68851 }, +{"pbcc", 2, one(0xf08f), one(0xffbf), "Bc", m68851 }, +{"pbccw", 2, one(0xf08f), one(0xffff), "BW", m68851 }, +{"pbcs", 2, one(0xf08e), one(0xffbf), "Bc", m68851 }, +{"pbcsw", 2, one(0xf08e), one(0xffff), "BW", m68851 }, +{"pbgc", 2, one(0xf08d), one(0xffbf), "Bc", m68851 }, +{"pbgcw", 2, one(0xf08d), one(0xffff), "BW", m68851 }, +{"pbgs", 2, one(0xf08c), one(0xffbf), "Bc", m68851 }, +{"pbgsw", 2, one(0xf08c), one(0xffff), "BW", m68851 }, +{"pbic", 2, one(0xf08b), one(0xffbf), "Bc", m68851 }, +{"pbicw", 2, one(0xf08b), one(0xffff), "BW", m68851 }, +{"pbis", 2, one(0xf08a), one(0xffbf), "Bc", m68851 }, +{"pbisw", 2, one(0xf08a), one(0xffff), "BW", m68851 }, +{"pblc", 2, one(0xf083), one(0xffbf), "Bc", m68851 }, +{"pblcw", 2, one(0xf083), one(0xffff), "BW", m68851 }, +{"pbls", 2, one(0xf082), one(0xffbf), "Bc", m68851 }, +{"pblsw", 2, one(0xf082), one(0xffff), "BW", m68851 }, +{"pbsc", 2, one(0xf085), one(0xffbf), "Bc", m68851 }, +{"pbscw", 2, one(0xf085), one(0xffff), "BW", m68851 }, +{"pbss", 2, one(0xf084), one(0xffbf), "Bc", m68851 }, +{"pbssw", 2, one(0xf084), one(0xffff), "BW", m68851 }, +{"pbwc", 2, one(0xf089), one(0xffbf), "Bc", m68851 }, +{"pbwcw", 2, one(0xf089), one(0xffff), "BW", m68851 }, +{"pbws", 2, one(0xf088), one(0xffbf), "Bc", m68851 }, +{"pbwsw", 2, one(0xf088), one(0xffff), "BW", m68851 }, + +{"pdbac", 4, two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbas", 4, two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbc", 4, two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbs", 4, two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcc", 4, two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcs", 4, two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgc", 4, two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgs", 4, two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbic", 4, two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbis", 4, two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdblc", 4, two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbls", 4, two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbsc", 4, two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbss", 4, two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbwc", 4, two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbws", 4, two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 }, + +{"pea", 2, one(0044100), one(0177700), "!s", m68000up|mcfisa_a }, + +{"pflusha", 2, one(0xf518), one(0xfff8), "", m68040up }, +{"pflusha", 4, two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 }, + +{"pflush", 4, two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 }, +{"pflush", 2, one(0xf508), one(0xfff8), "as", m68040up }, +{"pflush", 2, one(0xf508), one(0xfff8), "As", m68040up }, + +{"pflushan", 2, one(0xf510), one(0xfff8), "", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "as", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "As", m68040up }, + +{"pflushr", 4, two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 }, + +{"pflushs", 4, two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 }, + +{"ploadr", 4, two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, + +{"plpar", 2, one(0xf5c8), one(0xfff8), "as", m68060 }, +{"plpaw", 2, one(0xf588), one(0xfff8), "as", m68060 }, + +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 }, +{"pmove", 4, two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 }, +{"pmove", 4, two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 }, + +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "*l08", m68030 }, +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "|sW8", m68030 }, +{"pmovefd", 4, two(0xf000, 0x0900), two(0xffc0, 0xfbff), "*l38", m68030 }, + +{"prestore", 2, one(0xf140), one(0xffc0), "s", m68851 }, + +{"psac", 4, two(0xf040, 0x0007), two(0xffc0, 0xffff), "$s", m68851 }, +{"psas", 4, two(0xf040, 0x0006), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbc", 4, two(0xf040, 0x0001), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbs", 4, two(0xf040, 0x0000), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscc", 4, two(0xf040, 0x000f), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscs", 4, two(0xf040, 0x000e), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgc", 4, two(0xf040, 0x000d), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgs", 4, two(0xf040, 0x000c), two(0xffc0, 0xffff), "$s", m68851 }, +{"psic", 4, two(0xf040, 0x000b), two(0xffc0, 0xffff), "$s", m68851 }, +{"psis", 4, two(0xf040, 0x000a), two(0xffc0, 0xffff), "$s", m68851 }, +{"pslc", 4, two(0xf040, 0x0003), two(0xffc0, 0xffff), "$s", m68851 }, +{"psls", 4, two(0xf040, 0x0002), two(0xffc0, 0xffff), "$s", m68851 }, +{"pssc", 4, two(0xf040, 0x0005), two(0xffc0, 0xffff), "$s", m68851 }, +{"psss", 4, two(0xf040, 0x0004), two(0xffc0, 0xffff), "$s", m68851 }, +{"pswc", 4, two(0xf040, 0x0009), two(0xffc0, 0xffff), "$s", m68851 }, +{"psws", 4, two(0xf040, 0x0008), two(0xffc0, 0xffff), "$s", m68851 }, + +{"ptestr", 4, two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestr", 2, one(0xf568), one(0xfff8), "as", m68040 }, + +{"ptestw", 4, two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestw", 2, one(0xf548), one(0xfff8), "as", m68040 }, + +{"ptrapacw", 6, two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapacl", 6, two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapac", 4, two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapasw", 6, two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapasl", 6, two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapas", 4, two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbcw", 6, two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbcl", 6, two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbc", 4, two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbsw", 6, two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbsl", 6, two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbs", 4, two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapccw", 6, two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapccl", 6, two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcc", 4, two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapcsw", 6, two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapcsl", 6, two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcs", 4, two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgcw", 6, two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgcl", 6, two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgc", 4, two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgsw", 6, two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgsl", 6, two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgs", 4, two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapicw", 6, two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapicl", 6, two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapic", 4, two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapisw", 6, two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapisl", 6, two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapis", 4, two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplcw", 6, two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplcl", 6, two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 }, +{"ptraplc", 4, two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplsw", 6, two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplsl", 6, two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapls", 4, two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapscw", 6, two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapscl", 6, two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapsc", 4, two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapssw", 6, two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapssl", 6, two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapss", 4, two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwcw", 6, two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwcl", 6, two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapwc", 4, two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwsw", 6, two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwsl", 6, two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapws", 4, two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 }, + +{"pulse", 2, one(0045314), one(0177777), "", m68060 | mcfisa_a }, + +{"pvalid", 4, two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 }, +{"pvalid", 4, two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 }, + + /* FIXME: don't allow Dw==Dx. */ +{"remsl", 4, two(0x4c40, 0x0800), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, +{"remul", 4, two(0x4c40, 0x0000), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, + +{"reset", 2, one(0047160), one(0177777), "", m68000up }, + +{"rolb", 2, one(0160430), one(0170770), "QdDs", m68000up }, +{"rolb", 2, one(0160470), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0160530), one(0170770), "QdDs", m68000up }, +{"rolw", 2, one(0160570), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0163700), one(0177700), "~s", m68000up }, +{"roll", 2, one(0160630), one(0170770), "QdDs", m68000up }, +{"roll", 2, one(0160670), one(0170770), "DdDs", m68000up }, + +{"rorb", 2, one(0160030), one(0170770), "QdDs", m68000up }, +{"rorb", 2, one(0160070), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0160130), one(0170770), "QdDs", m68000up }, +{"rorw", 2, one(0160170), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0163300), one(0177700), "~s", m68000up }, +{"rorl", 2, one(0160230), one(0170770), "QdDs", m68000up }, +{"rorl", 2, one(0160270), one(0170770), "DdDs", m68000up }, + +{"roxlb", 2, one(0160420), one(0170770), "QdDs", m68000up }, +{"roxlb", 2, one(0160460), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0160520), one(0170770), "QdDs", m68000up }, +{"roxlw", 2, one(0160560), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0162700), one(0177700), "~s", m68000up }, +{"roxll", 2, one(0160620), one(0170770), "QdDs", m68000up }, +{"roxll", 2, one(0160660), one(0170770), "DdDs", m68000up }, + +{"roxrb", 2, one(0160020), one(0170770), "QdDs", m68000up }, +{"roxrb", 2, one(0160060), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0160120), one(0170770), "QdDs", m68000up }, +{"roxrw", 2, one(0160160), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0162300), one(0177700), "~s", m68000up }, +{"roxrl", 2, one(0160220), one(0170770), "QdDs", m68000up }, +{"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up }, + +{"rtd", 4, one(0047164), one(0177777), "#w", m68010up }, + +{"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a }, + +{"rtm", 2, one(0003300), one(0177760), "Rs", m68020 }, + +{"rtr", 2, one(0047167), one(0177777), "", m68000up }, + +{"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a }, + +{"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b }, + +{"sbcd", 2, one(0100400), one(0170770), "DsDd", m68000up }, +{"sbcd", 2, one(0100410), one(0170770), "-s-d", m68000up }, + +{"scc", 2, one(0052300), one(0177700), "$s", m68000up }, +{"scc", 2, one(0052300), one(0177700), "Ds", mcfisa_a }, +{"scs", 2, one(0052700), one(0177700), "$s", m68000up }, +{"scs", 2, one(0052700), one(0177700), "Ds", mcfisa_a }, +{"seq", 2, one(0053700), one(0177700), "$s", m68000up }, +{"seq", 2, one(0053700), one(0177700), "Ds", mcfisa_a }, +{"sf", 2, one(0050700), one(0177700), "$s", m68000up }, +{"sf", 2, one(0050700), one(0177700), "Ds", mcfisa_a }, +{"sge", 2, one(0056300), one(0177700), "$s", m68000up }, +{"sge", 2, one(0056300), one(0177700), "Ds", mcfisa_a }, +{"sgt", 2, one(0057300), one(0177700), "$s", m68000up }, +{"sgt", 2, one(0057300), one(0177700), "Ds", mcfisa_a }, +{"shi", 2, one(0051300), one(0177700), "$s", m68000up }, +{"shi", 2, one(0051300), one(0177700), "Ds", mcfisa_a }, +{"sle", 2, one(0057700), one(0177700), "$s", m68000up }, +{"sle", 2, one(0057700), one(0177700), "Ds", mcfisa_a }, +{"sls", 2, one(0051700), one(0177700), "$s", m68000up }, +{"sls", 2, one(0051700), one(0177700), "Ds", mcfisa_a }, +{"slt", 2, one(0056700), one(0177700), "$s", m68000up }, +{"slt", 2, one(0056700), one(0177700), "Ds", mcfisa_a }, +{"smi", 2, one(0055700), one(0177700), "$s", m68000up }, +{"smi", 2, one(0055700), one(0177700), "Ds", mcfisa_a }, +{"sne", 2, one(0053300), one(0177700), "$s", m68000up }, +{"sne", 2, one(0053300), one(0177700), "Ds", mcfisa_a }, +{"spl", 2, one(0055300), one(0177700), "$s", m68000up }, +{"spl", 2, one(0055300), one(0177700), "Ds", mcfisa_a }, +{"st", 2, one(0050300), one(0177700), "$s", m68000up }, +{"st", 2, one(0050300), one(0177700), "Ds", mcfisa_a }, +{"svc", 2, one(0054300), one(0177700), "$s", m68000up }, +{"svc", 2, one(0054300), one(0177700), "Ds", mcfisa_a }, +{"svs", 2, one(0054700), one(0177700), "$s", m68000up }, +{"svs", 2, one(0054700), one(0177700), "Ds", mcfisa_a }, + +{"stop", 4, one(0047162), one(0177777), "#w", m68000up | mcfisa_a }, + +{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa}, + +{"subal", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subaw", 2, one(0110300), one(0170700), "*wAd", m68000up }, + +{"subib", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subiw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, + +{"subqb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subqw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subql", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, + +/* The sub opcode can generate the suba, subi, and subq instructions. */ +{"subb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subb", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subb", 2, one(0110000), one(0170700), ";bDd", m68000up }, +{"subb", 2, one(0110400), one(0170700), "Dd~s", m68000up }, +{"subw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subw", 2, one(0110300), one(0170700), "*wAd", m68000up }, +{"subw", 2, one(0110100), one(0170700), "*wDd", m68000up }, +{"subw", 2, one(0110500), one(0170700), "Dd~s", m68000up }, +{"subl", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, +{"subl", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subl", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, +{"subl", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subl", 2, one(0110200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"subl", 2, one(0110600), one(0170700), "Dd~s", m68000up | mcfisa_a }, + +{"subxb", 2, one(0110400), one(0170770), "DsDd", m68000up }, +{"subxb", 2, one(0110410), one(0170770), "-s-d", m68000up }, +{"subxw", 2, one(0110500), one(0170770), "DsDd", m68000up }, +{"subxw", 2, one(0110510), one(0170770), "-s-d", m68000up }, +{"subxl", 2, one(0110600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"subxl", 2, one(0110610), one(0170770), "-s-d", m68000up }, + +{"swap", 2, one(0044100), one(0177770), "Ds", m68000up | mcfisa_a }, + +/* swbeg and swbegl are magic constants used on sysV68. The compiler + generates them before a switch table. They tell the debugger and + disassembler that a switch table follows. The parameter is the + number of elements in the table. swbeg means that the entries in + the table are word (2 byte) sized, and swbegl means that the + entries in the table are longword (4 byte) sized. */ +{"swbeg", 4, one(0045374), one(0177777), "#w", m68000up | mcfisa_a }, +{"swbegl", 6, one(0045375), one(0177777), "#l", m68000up | mcfisa_a }, + +{"tas", 2, one(0045300), one(0177700), "$s", m68000up | mcfisa_b}, + +#define TBL1(name,insn_size,signed,round,size) \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400), \ + two(0177700,0107777), "!sD1", cpu32 }, \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)), \ + two(0177770,0107770), "DsD3D1", cpu32 } +#define TBL(name1, name2, name3, s, r) \ + TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2) +TBL("tblsb", "tblsw", "tblsl", 2, 1), +TBL("tblsnb", "tblsnw", "tblsnl", 2, 0), +TBL("tblub", "tbluw", "tblul", 0, 1), +TBL("tblunb", "tblunw", "tblunl", 0, 0), + +{"trap", 2, one(0047100), one(0177760), "Ts", m68000up | mcfisa_a }, + +{"trapcc", 2, one(0052374), one(0177777), "", m68020up | cpu32 }, +{"trapcs", 2, one(0052774), one(0177777), "", m68020up | cpu32 }, +{"trapeq", 2, one(0053774), one(0177777), "", m68020up | cpu32 }, +{"trapf", 2, one(0050774), one(0177777), "", m68020up | cpu32 | mcfisa_a }, +{"trapge", 2, one(0056374), one(0177777), "", m68020up | cpu32 }, +{"trapgt", 2, one(0057374), one(0177777), "", m68020up | cpu32 }, +{"traphi", 2, one(0051374), one(0177777), "", m68020up | cpu32 }, +{"traple", 2, one(0057774), one(0177777), "", m68020up | cpu32 }, +{"trapls", 2, one(0051774), one(0177777), "", m68020up | cpu32 }, +{"traplt", 2, one(0056774), one(0177777), "", m68020up | cpu32 }, +{"trapmi", 2, one(0055774), one(0177777), "", m68020up | cpu32 }, +{"trapne", 2, one(0053374), one(0177777), "", m68020up | cpu32 }, +{"trappl", 2, one(0055374), one(0177777), "", m68020up | cpu32 }, +{"trapt", 2, one(0050374), one(0177777), "", m68020up | cpu32 }, +{"trapvc", 2, one(0054374), one(0177777), "", m68020up | cpu32 }, +{"trapvs", 2, one(0054774), one(0177777), "", m68020up | cpu32 }, + +{"trapccw", 4, one(0052372), one(0177777), "#w", m68020up|cpu32 }, +{"trapcsw", 4, one(0052772), one(0177777), "#w", m68020up|cpu32 }, +{"trapeqw", 4, one(0053772), one(0177777), "#w", m68020up|cpu32 }, +{"trapfw", 4, one(0050772), one(0177777), "#w", m68020up|cpu32|mcfisa_a}, +{"trapgew", 4, one(0056372), one(0177777), "#w", m68020up|cpu32 }, +{"trapgtw", 4, one(0057372), one(0177777), "#w", m68020up|cpu32 }, +{"traphiw", 4, one(0051372), one(0177777), "#w", m68020up|cpu32 }, +{"traplew", 4, one(0057772), one(0177777), "#w", m68020up|cpu32 }, +{"traplsw", 4, one(0051772), one(0177777), "#w", m68020up|cpu32 }, +{"trapltw", 4, one(0056772), one(0177777), "#w", m68020up|cpu32 }, +{"trapmiw", 4, one(0055772), one(0177777), "#w", m68020up|cpu32 }, +{"trapnew", 4, one(0053372), one(0177777), "#w", m68020up|cpu32 }, +{"trapplw", 4, one(0055372), one(0177777), "#w", m68020up|cpu32 }, +{"traptw", 4, one(0050372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvcw", 4, one(0054372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvsw", 4, one(0054772), one(0177777), "#w", m68020up|cpu32 }, + +{"trapccl", 6, one(0052373), one(0177777), "#l", m68020up|cpu32 }, +{"trapcsl", 6, one(0052773), one(0177777), "#l", m68020up|cpu32 }, +{"trapeql", 6, one(0053773), one(0177777), "#l", m68020up|cpu32 }, +{"trapfl", 6, one(0050773), one(0177777), "#l", m68020up|cpu32|mcfisa_a}, +{"trapgel", 6, one(0056373), one(0177777), "#l", m68020up|cpu32 }, +{"trapgtl", 6, one(0057373), one(0177777), "#l", m68020up|cpu32 }, +{"traphil", 6, one(0051373), one(0177777), "#l", m68020up|cpu32 }, +{"traplel", 6, one(0057773), one(0177777), "#l", m68020up|cpu32 }, +{"traplsl", 6, one(0051773), one(0177777), "#l", m68020up|cpu32 }, +{"trapltl", 6, one(0056773), one(0177777), "#l", m68020up|cpu32 }, +{"trapmil", 6, one(0055773), one(0177777), "#l", m68020up|cpu32 }, +{"trapnel", 6, one(0053373), one(0177777), "#l", m68020up|cpu32 }, +{"trappll", 6, one(0055373), one(0177777), "#l", m68020up|cpu32 }, +{"traptl", 6, one(0050373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvcl", 6, one(0054373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvsl", 6, one(0054773), one(0177777), "#l", m68020up|cpu32 }, + +{"trapv", 2, one(0047166), one(0177777), "", m68000up }, + +{"tstb", 2, one(0045000), one(0177700), ";b", m68020up|cpu32|mcfisa_a }, +{"tstb", 2, one(0045000), one(0177700), "$b", m68000up }, +{"tstw", 2, one(0045100), one(0177700), "*w", m68020up|cpu32|mcfisa_a }, +{"tstw", 2, one(0045100), one(0177700), "$w", m68000up }, +{"tstl", 2, one(0045200), one(0177700), "*l", m68020up|cpu32|mcfisa_a }, +{"tstl", 2, one(0045200), one(0177700), "$l", m68000up }, + +{"unlk", 2, one(0047130), one(0177770), "As", m68000up | mcfisa_a }, + +{"unpk", 4, one(0100600), one(0170770), "DsDd#w", m68020up }, +{"unpk", 4, one(0100610), one(0170770), "-s-d#w", m68020up }, + +{"wddatab", 2, one(0175400), one(0177700), "~s", mcfisa_a }, +{"wddataw", 2, one(0175500), one(0177700), "~s", mcfisa_a }, +{"wddatal", 2, one(0175600), one(0177700), "~s", mcfisa_a }, + +{"wdebug", 4, two(0175720, 03), two(0177770, 0xffff), "as", mcfisa_a }, +{"wdebug", 4, two(0175750, 03), two(0177770, 0xffff), "ds", mcfisa_a }, +}; + +const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0]; + +/* These aliases used to be in the above table, each one duplicating + all of the entries for its primary exactly. This table was + constructed by mechanical processing of the opcode table, with a + small number of tweaks done by hand. There are probably a lot more + aliases above that could be moved down here, except for very minor + differences. */ + +const struct m68k_opcode_alias m68k_opcode_aliases[] = +{ + { "add", "addw", }, + { "adda", "addaw", }, + { "addi", "addiw", }, + { "addq", "addqw", }, + { "addx", "addxw", }, + { "asl", "aslw", }, + { "asr", "asrw", }, + { "bhi", "bhiw", }, + { "bls", "blsw", }, + { "bcc", "bccw", }, + { "bcs", "bcsw", }, + { "bne", "bnew", }, + { "beq", "beqw", }, + { "bvc", "bvcw", }, + { "bvs", "bvsw", }, + { "bpl", "bplw", }, + { "bmi", "bmiw", }, + { "bge", "bgew", }, + { "blt", "bltw", }, + { "bgt", "bgtw", }, + { "ble", "blew", }, + { "bra", "braw", }, + { "bsr", "bsrw", }, + { "bhib", "bhis", }, + { "blsb", "blss", }, + { "bccb", "bccs", }, + { "bcsb", "bcss", }, + { "bneb", "bnes", }, + { "beqb", "beqs", }, + { "bvcb", "bvcs", }, + { "bvsb", "bvss", }, + { "bplb", "bpls", }, + { "bmib", "bmis", }, + { "bgeb", "bges", }, + { "bltb", "blts", }, + { "bgtb", "bgts", }, + { "bleb", "bles", }, + { "brab", "bras", }, + { "bsrb", "bsrs", }, + { "bhs", "bccw" }, + { "bhss", "bccs" }, + { "bhsb", "bccs" }, + { "bhsw", "bccw" }, + { "bhsl", "bccl" }, + { "blo", "bcsw" }, + { "blos", "bcss" }, + { "blob", "bcss" }, + { "blow", "bcsw" }, + { "blol", "bcsl" }, + { "br", "braw", }, + { "brs", "bras", }, + { "brb", "bras", }, + { "brw", "braw", }, + { "brl", "bral", }, + { "jfnlt", "bcc", }, /* Apparently a sun alias. */ + { "jfngt", "ble", }, /* Apparently a sun alias. */ + { "jfeq", "beqs", }, /* Apparently a sun alias. */ + { "bchgb", "bchg", }, + { "bchgl", "bchg", }, + { "bclrb", "bclr", }, + { "bclrl", "bclr", }, + { "bsetb", "bset", }, + { "bsetl", "bset", }, + { "btstb", "btst", }, + { "btstl", "btst", }, + { "cas2", "cas2w", }, + { "cas", "casw", }, + { "chk2", "chk2w", }, + { "chk", "chkw", }, + { "clr", "clrw", }, + { "cmp2", "cmp2w", }, + { "cmpa", "cmpaw", }, + { "cmpi", "cmpiw", }, + { "cmpm", "cmpmw", }, + { "cmp", "cmpw", }, + { "dbccw", "dbcc", }, + { "dbcsw", "dbcs", }, + { "dbeqw", "dbeq", }, + { "dbfw", "dbf", }, + { "dbgew", "dbge", }, + { "dbgtw", "dbgt", }, + { "dbhiw", "dbhi", }, + { "dblew", "dble", }, + { "dblsw", "dbls", }, + { "dbltw", "dblt", }, + { "dbmiw", "dbmi", }, + { "dbnew", "dbne", }, + { "dbplw", "dbpl", }, + { "dbtw", "dbt", }, + { "dbvcw", "dbvc", }, + { "dbvsw", "dbvs", }, + { "dbhs", "dbcc", }, + { "dbhsw", "dbcc", }, + { "dbra", "dbf", }, + { "dbraw", "dbf", }, + { "tdivsl", "divsl", }, + { "divs", "divsw", }, + { "divu", "divuw", }, + { "ext", "extw", }, + { "extbw", "extw", }, + { "extwl", "extl", }, + { "fbneq", "fbne", }, + { "fbsneq", "fbsne", }, + { "fdbneq", "fdbne", }, + { "fdbsneq", "fdbsne", }, + { "fmovecr", "fmovecrx", }, + { "fmovm", "fmovem", }, + { "fsneq", "fsne", }, + { "fssneq", "fssne", }, + { "ftrapneq", "ftrapne", }, + { "ftrapsneq", "ftrapsne", }, + { "fjneq", "fjne", }, + { "fjsneq", "fjsne", }, + { "jmpl", "jmp", }, + { "jmps", "jmp", }, + { "jsrl", "jsr", }, + { "jsrs", "jsr", }, + { "leal", "lea", }, + { "lsl", "lslw", }, + { "lsr", "lsrw", }, + { "mac", "macw" }, + { "movea", "moveaw", }, + { "movem", "movemw", }, + { "movml", "moveml", }, + { "movmw", "movemw", }, + { "movm", "movemw", }, + { "movep", "movepw", }, + { "movpw", "movepw", }, + { "moves", "movesw" }, + { "muls", "mulsw", }, + { "mulu", "muluw", }, + { "msac", "msacw" }, + { "nbcdb", "nbcd" }, + { "neg", "negw", }, + { "negx", "negxw", }, + { "not", "notw", }, + { "peal", "pea", }, + { "rol", "rolw", }, + { "ror", "rorw", }, + { "roxl", "roxlw", }, + { "roxr", "roxrw", }, + { "sats", "satsl", }, + { "sbcdb", "sbcd", }, + { "sccb", "scc", }, + { "scsb", "scs", }, + { "seqb", "seq", }, + { "sfb", "sf", }, + { "sgeb", "sge", }, + { "sgtb", "sgt", }, + { "shib", "shi", }, + { "sleb", "sle", }, + { "slsb", "sls", }, + { "sltb", "slt", }, + { "smib", "smi", }, + { "sneb", "sne", }, + { "splb", "spl", }, + { "stb", "st", }, + { "svcb", "svc", }, + { "svsb", "svs", }, + { "sfge", "sge", }, + { "sfgt", "sgt", }, + { "sfle", "sle", }, + { "sflt", "slt", }, + { "sfneq", "sne", }, + { "suba", "subaw", }, + { "subi", "subiw", }, + { "subq", "subqw", }, + { "sub", "subw", }, + { "subx", "subxw", }, + { "swapw", "swap", }, + { "tasb", "tas", }, + { "tpcc", "trapcc", }, + { "tcc", "trapcc", }, + { "tst", "tstw", }, + { "jbra", "jra", }, + { "jbhi", "jhi", }, + { "jbls", "jls", }, + { "jbcc", "jcc", }, + { "jbcs", "jcs", }, + { "jbne", "jne", }, + { "jbeq", "jeq", }, + { "jbvc", "jvc", }, + { "jbvs", "jvs", }, + { "jbpl", "jpl", }, + { "jbmi", "jmi", }, + { "jbge", "jge", }, + { "jblt", "jlt", }, + { "jbgt", "jgt", }, + { "jble", "jle", }, + { "movql", "moveq", }, + { "moveql", "moveq", }, + { "movl", "movel", }, + { "movq", "moveq", }, + { "moval", "moveal", }, + { "movaw", "moveaw", }, + { "movb", "moveb", }, + { "movc", "movec", }, + { "movecl", "movec", }, + { "movpl", "movepl", }, + { "movw", "movew", }, + { "movsb", "movesb", }, + { "movsl", "movesl", }, + { "movsw", "movesw", }, + { "mov3q", "mov3ql", }, + + { "tdivul", "divul", }, /* For m68k-svr4. */ + { "fmovb", "fmoveb", }, + { "fsmovb", "fsmoveb", }, + { "fdmovb", "fdmoveb", }, + { "fmovd", "fmoved", }, + { "fsmovd", "fsmoved", }, + { "fmovl", "fmovel", }, + { "fsmovl", "fsmovel", }, + { "fdmovl", "fdmovel", }, + { "fmovp", "fmovep", }, + { "fsmovp", "fsmovep", }, + { "fdmovp", "fdmovep", }, + { "fmovs", "fmoves", }, + { "fsmovs", "fsmoves", }, + { "fdmovs", "fdmoves", }, + { "fmovw", "fmovew", }, + { "fsmovw", "fsmovew", }, + { "fdmovw", "fdmovew", }, + { "fmovx", "fmovex", }, + { "fsmovx", "fsmovex", }, + { "fdmovx", "fdmovex", }, + { "fmovcr", "fmovecr", }, + { "fmovcrx", "fmovecrx", }, + { "ftestb", "ftstb", }, + { "ftestd", "ftstd", }, + { "ftestl", "ftstl", }, + { "ftestp", "ftstp", }, + { "ftests", "ftsts", }, + { "ftestw", "ftstw", }, + { "ftestx", "ftstx", }, + + { "bitrevl", "bitrev", }, + { "byterevl", "byterev", }, + { "ff1l", "ff1", }, + +}; + +const int m68k_numaliases = + sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0]; +/* **** End of m68k-opc.c */ +/* **** floatformat.c from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +/* This is needed to pick up the NAN macro on some systems. */ +//#define _GNU_SOURCE + +#ifndef INFINITY +#ifdef HUGE_VAL +#define INFINITY HUGE_VAL +#else +#define INFINITY (1.0 / 0.0) +#endif +#endif + +#ifndef NAN +#define NAN (0.0 / 0.0) +#endif + +static unsigned long get_field (const unsigned char *, + enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int); +static int floatformat_always_valid (const struct floatformat *fmt, + const char *from); + +static int +floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, + const char *from ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +/* floatformats for IEEE single and double, big and little endian. */ +const struct floatformat floatformat_ieee_single_big = +{ + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_single_little = +{ + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_big = +{ + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_little = +{ + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_little", + floatformat_always_valid +}; + +/* floatformat for IEEE double, little endian byte order, with big endian word + ordering, as on the ARM. */ + +const struct floatformat floatformat_ieee_double_littlebyte_bigword = +{ + floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_littlebyte_bigword", + floatformat_always_valid +}; + +static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from); + +static int +floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from) +{ + /* In the i387 double-extended format, if the exponent is all ones, + then the integer bit must be set. If the exponent is neither 0 + nor ~0, the intbit must also be set. Only if the exponent is + zero can it be zero, and then it must be zero. */ + unsigned long exponent, int_bit; + const unsigned char *ufrom = (const unsigned char *) from; + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->man_start, 1); + + if ((exponent == 0) != (int_bit == 0)) + return 0; + else + return 1; +} + +const struct floatformat floatformat_i387_ext = +{ + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_i387_ext", + floatformat_i387_ext_is_valid +}; +const struct floatformat floatformat_m68881_ext = +{ + /* Note that the bits from 16 to 31 are unused. */ + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_m68881_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_i960_ext = +{ + /* Note that the bits from 0 to 15 are unused. */ + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_i960_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_ext = +{ + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_m88110_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_harris_ext = +{ + /* Harris uses raw format 128 bytes long, but the number is just an ieee + double, and the last 64 bits are wasted. */ + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, + floatformat_intbit_no, + "floatformat_m88110_ext_harris", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_big = +{ + /* Bits 1 to 16 are unused. */ + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_big", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_littlebyte_bigword = +{ + /* Bits 1 to 16 are unused. */ + floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_littlebyte_bigword", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_big = +{ + floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_little = +{ + floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_big = +{ + floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_little = +{ + floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_little", + floatformat_always_valid +}; + +/* Extract a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (const unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len) +{ + unsigned long result; + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + result = *(data + cur_byte) >> (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + /* This is the last byte; zero out the bits which are not part of + this field. */ + result |= + (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) + << cur_bitshift; + else + result |= *(data + cur_byte) << cur_bitshift; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } + return result; +} + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +floatformat_to_double (const struct floatformat *fmt, + const char *from, double *to) +{ + const unsigned char *ufrom = (const unsigned char *)from; + double dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + int special_exponent; /* It's a NaN, denorm or zero */ + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + + /* If the exponent indicates a NaN, we don't have information to + decide what to do. So we handle it like IEEE, except that we + don't try to preserve the type of NaN. FIXME. */ + if ((unsigned long) exponent == fmt->exp_nan) + { + int nan; + + mant_off = fmt->man_start; + mant_bits_left = fmt->man_len; + nan = 0; + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits) != 0) + { + /* This is a NaN. */ + nan = 1; + break; + } + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* On certain systems (such as GNU/Linux), the use of the + INFINITY macro below may generate a warning that can not be + silenced due to a bug in GCC (PR preprocessor/11931). The + preprocessor fails to recognise the __extension__ keyword in + conjunction with the GNU/C99 extension for hexadecimal + floating point constants and will issue a warning when + compiling with -pedantic. */ + if (nan) + dto = NAN; + else + dto = INFINITY; + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + + *to = dto; + + return; + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + + special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; + + /* Don't bias zero's, denorms or NaNs. */ + if (!special_exponent) + exponent -= fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + + /* If this format uses a hidden bit, explicitly add it in now. Otherwise, + increment the exponent by one to account for the integer bit. */ + + if (!special_exponent) + { + if (fmt->intbit == floatformat_intbit_no) + dto = ldexp (1.0, exponent); + else + exponent++; + } + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + /* Handle denormalized numbers. FIXME: What should we do for + non-IEEE formats? */ + if (exponent == 0 && mant != 0) + dto += ldexp ((double)mant, + (- fmt->exp_bias + - mant_bits + - (mant_off - fmt->man_start) + + 1)); + else + dto += ldexp ((double)mant, exponent - mant_bits); + if (exponent != 0) + exponent -= mant_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + *to = dto; +} + +static void put_field (unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int, + unsigned long); + +/* Set a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len, + unsigned long stuff_to_put) +{ + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + *(data + cur_byte) &= + ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); + *(data + cur_byte) |= + (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + { + /* This is the last byte. */ + *(data + cur_byte) &= + ~((1 << (len - cur_bitshift)) - 1); + *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); + } + else + *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) + & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_double (const struct floatformat *fmt, + const double *from, char *to) +{ + double dfrom; + int exponent; + double mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *)to; + + dfrom = *from; + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); + dfrom = -dfrom; + } + + if (dfrom == 0) + { + /* 0.0. */ + return; + } + + if (dfrom != dfrom) + { + /* NaN. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + /* Be sure it's not infinity, but NaN value is irrelevant. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, + 32, 1); + return; + } + + if (dfrom + dfrom == dfrom) + { + /* This can only happen for an infinite value (or zero, which we + already handled above). */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + return; + } + + mant = frexp (dfrom, &exponent); + if (exponent + fmt->exp_bias - 1 > 0) + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, exponent + fmt->exp_bias - 1); + else + { + /* Handle a denormalized number. FIXME: What should we do for + non-IEEE formats? */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + mant = ldexp (mant, exponent + fmt->exp_bias - 1); + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = (unsigned long)mant; + mant -= mant_long; + + /* If the integer bit is implicit, and we are not creating a + denormalized number, then we need to discard it. */ + if ((unsigned int) mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no + && exponent + fmt->exp_bias - 1 > 0) + { + mant_long &= 0x7fffffff; + mant_bits -= 1; + } + else if (mant_bits < 32) + { + /* The bits we want are in the most significant MANT_BITS bits of + mant_long. Move them to the least significant. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } +} + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +int +floatformat_is_valid (const struct floatformat *fmt, const char *from) +{ + return fmt->is_valid (fmt, from); +} + + +#ifdef IEEE_DEBUG + +/* This is to be run on a host which uses IEEE floating point. */ + +void +ieee_test (double n) +{ + double result; + + floatformat_to_double (&floatformat_ieee_double_little, (char *) &n, + &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(to): %.20g -> %.20g\n", n, result); + + floatformat_from_double (&floatformat_ieee_double_little, &n, + (char *) &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(from): %.20g -> %.20g\n", n, result); + +#if 0 + { + char exten[16]; + + floatformat_from_double (&floatformat_m68881_ext, &n, exten); + floatformat_to_double (&floatformat_m68881_ext, exten, &result); + if (n != result) + printf ("Differ(to+from): %.20g -> %.20g\n", n, result); + } +#endif + +#if IEEE_DEBUG > 1 + /* This is to be run on a host which uses 68881 format. */ + { + long double ex = *(long double *)exten; + if (ex != n) + printf ("Differ(from vs. extended): %.20g\n", n); + } +#endif +} + +int +main (void) +{ + ieee_test (0.0); + ieee_test (0.5); + ieee_test (256.0); + ieee_test (0.12345); + ieee_test (234235.78907234); + ieee_test (-512.0); + ieee_test (-0.004321); + ieee_test (1.2E-70); + ieee_test (1.2E-316); + ieee_test (4.9406564584124654E-324); + ieee_test (- 4.9406564584124654E-324); + ieee_test (- 0.0); + ieee_test (- INFINITY); + ieee_test (- NAN); + ieee_test (INFINITY); + ieee_test (NAN); + return 0; +} +#endif +/* **** End of floatformat.c */ diff --git a/qemu/qemu-git/m68k.ld b/qemu/qemu-git/m68k.ld new file mode 100644 index 0000000..0e3d9de --- /dev/null +++ b/qemu/qemu-git/m68k.ld @@ -0,0 +1,175 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", + "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x4e754e75 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x4e754e75 + .fini : + { + KEEP (*(.fini)) + } =0x4e754e75 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x2000) + (. & (0x2000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/qemu/qemu-git/microblaze-dis.c b/qemu/qemu-git/microblaze-dis.c new file mode 100644 index 0000000..aa68f16 --- /dev/null +++ b/qemu/qemu-git/microblaze-dis.c @@ -0,0 +1,1102 @@ +/* Disassemble Xilinx microblaze instructions. + Copyright (C) 1993, 1999, 2000 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#include +#define STATIC_TABLE +#define DEFINE_TABLE + +#define TRUE 1 +#define FALSE 0 + +#ifndef MICROBLAZE_OPC +#define MICROBLAZE_OPC +/* Assembler instructions for Xilinx's microblaze processor + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#ifndef MICROBLAZE_OPCM +#define MICROBLAZE_OPCM + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + * $Header: + */ + +enum microblaze_instr { + add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu, + addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul, mulh, mulhu, mulhsu, + idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput, + ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor, + andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, wdcclear, wdcflush, mts, mfs, br, brd, + brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt, + bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni, + imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid, + brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti, + bgtid, bgei, bgeid, lbu, lhu, lw, lwx, sb, sh, sw, swx, lbui, lhui, lwi, + sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv, + fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, flt, fint, fsqrt, + tget, tcget, tnget, tncget, tput, tcput, tnput, tncput, + eget, ecget, neget, necget, eput, ecput, neput, necput, + teget, tecget, tneget, tnecget, teput, tecput, tneput, tnecput, + aget, caget, naget, ncaget, aput, caput, naput, ncaput, + taget, tcaget, tnaget, tncaget, taput, tcaput, tnaput, tncaput, + eaget, ecaget, neaget, necaget, eaput, ecaput, neaput, necaput, + teaget, tecaget, tneaget, tnecaget, teaput, tecaput, tneaput, tnecaput, + getd, tgetd, cgetd, tcgetd, ngetd, tngetd, ncgetd, tncgetd, + putd, tputd, cputd, tcputd, nputd, tnputd, ncputd, tncputd, + egetd, tegetd, ecgetd, tecgetd, negetd, tnegetd, necgetd, tnecgetd, + eputd, teputd, ecputd, tecputd, neputd, tneputd, necputd, tnecputd, + agetd, tagetd, cagetd, tcagetd, nagetd, tnagetd, ncagetd, tncagetd, + aputd, taputd, caputd, tcaputd, naputd, tnaputd, ncaputd, tncaputd, + eagetd, teagetd, ecagetd, tecagetd, neagetd, tneagetd, necagetd, tnecagetd, + eaputd, teaputd, ecaputd, tecaputd, neaputd, tneaputd, necaputd, tnecaputd, + invalid_inst } ; + +enum microblaze_instr_type { + arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst, + return_inst, immediate_inst, special_inst, memory_load_inst, + memory_store_inst, barrel_shift_inst, anyware_inst }; + +#define INST_WORD_SIZE 4 + +/* gen purpose regs go from 0 to 31 */ +/* mask is reg num - max_reg_num, ie reg_num - 32 in this case */ + +#define REG_PC_MASK 0x8000 +#define REG_MSR_MASK 0x8001 +#define REG_EAR_MASK 0x8003 +#define REG_ESR_MASK 0x8005 +#define REG_FSR_MASK 0x8007 +#define REG_BTR_MASK 0x800b +#define REG_EDR_MASK 0x800d +#define REG_PVR_MASK 0xa000 + +#define REG_PID_MASK 0x9000 +#define REG_ZPR_MASK 0x9001 +#define REG_TLBX_MASK 0x9002 +#define REG_TLBLO_MASK 0x9003 +#define REG_TLBHI_MASK 0x9004 +#define REG_TLBSX_MASK 0x9005 + +#define MIN_REGNUM 0 +#define MAX_REGNUM 31 + +#define MIN_PVR_REGNUM 0 +#define MAX_PVR_REGNUM 15 + +#define REG_PC 32 /* PC */ +#define REG_MSR 33 /* machine status reg */ +#define REG_EAR 35 /* Exception reg */ +#define REG_ESR 37 /* Exception reg */ +#define REG_FSR 39 /* FPU Status reg */ +#define REG_BTR 43 /* Branch Target reg */ +#define REG_EDR 45 /* Exception reg */ +#define REG_PVR 40960 /* Program Verification reg */ + +#define REG_PID 36864 /* MMU: Process ID reg */ +#define REG_ZPR 36865 /* MMU: Zone Protect reg */ +#define REG_TLBX 36866 /* MMU: TLB Index reg */ +#define REG_TLBLO 36867 /* MMU: TLB Low reg */ +#define REG_TLBHI 36868 /* MMU: TLB High reg */ +#define REG_TLBSX 36869 /* MMU: TLB Search Index reg */ + +/* alternate names for gen purpose regs */ +#define REG_SP 1 /* stack pointer */ +#define REG_ROSDP 2 /* read-only small data pointer */ +#define REG_RWSDP 13 /* read-write small data pointer */ + +/* Assembler Register - Used in Delay Slot Optimization */ +#define REG_AS 18 +#define REG_ZERO 0 + +#define RD_LOW 21 /* low bit for RD */ +#define RA_LOW 16 /* low bit for RA */ +#define RB_LOW 11 /* low bit for RB */ +#define IMM_LOW 0 /* low bit for immediate */ + +#define RD_MASK 0x03E00000 +#define RA_MASK 0x001F0000 +#define RB_MASK 0x0000F800 +#define IMM_MASK 0x0000FFFF + +// imm mask for barrel shifts +#define IMM5_MASK 0x0000001F + + +// FSL imm mask for get, put instructions +#define RFSL_MASK 0x000000F + +// imm mask for msrset, msrclr instructions +#define IMM15_MASK 0x00007FFF + +#endif /* MICROBLAZE-OPCM */ + +#define INST_TYPE_RD_R1_R2 0 +#define INST_TYPE_RD_R1_IMM 1 +#define INST_TYPE_RD_R1_UNSIGNED_IMM 2 +#define INST_TYPE_RD_R1 3 +#define INST_TYPE_RD_R2 4 +#define INST_TYPE_RD_IMM 5 +#define INST_TYPE_R2 6 +#define INST_TYPE_R1_R2 7 +#define INST_TYPE_R1_IMM 8 +#define INST_TYPE_IMM 9 +#define INST_TYPE_SPECIAL_R1 10 +#define INST_TYPE_RD_SPECIAL 11 +#define INST_TYPE_R1 12 + // new instn type for barrel shift imms +#define INST_TYPE_RD_R1_IMM5 13 +#define INST_TYPE_RD_RFSL 14 +#define INST_TYPE_R1_RFSL 15 + + // new insn type for insn cache +#define INST_TYPE_RD_R1_SPECIAL 16 + +// new insn type for msrclr, msrset insns. +#define INST_TYPE_RD_IMM15 17 + +// new insn type for tuqula rd - addik rd, r0, 42 +#define INST_TYPE_RD 18 + +// new insn type for t*put +#define INST_TYPE_RFSL 19 + +#define INST_TYPE_NONE 25 + + + +#define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/ +#define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/ + +#define IMMVAL_MASK_NON_SPECIAL 0x0000 +#define IMMVAL_MASK_MTS 0x4000 +#define IMMVAL_MASK_MFS 0x0000 + +#define OPCODE_MASK_H 0xFC000000 /* High 6 bits only */ +#define OPCODE_MASK_H1 0xFFE00000 /* High 11 bits */ +#define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16 */ +#define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */ +#define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits */ +#define OPCODE_MASK_H13S 0xFFE0EFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H23S 0xFC1FC000 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */ +#define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */ +#define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */ +#define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits */ +#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */ +#define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22 */ +#define OPCODE_MASK_H32 0xFC00FC00 /* High 6 bits and bit 16-21 */ +#define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits */ +#define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26 */ + +// New Mask for msrset, msrclr insns. +#define OPCODE_MASK_H23N 0xFC1F8000 /* High 6 and bits 11 - 16 */ + +#define DELAY_SLOT 1 +#define NO_DELAY_SLOT 0 + +#define MAX_OPCODES 280 + +struct op_code_struct { + const char *name; + short inst_type; /* registers and immediate values involved */ + short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */ + short delay_slots; /* info about delay slots needed after this instr. */ + short immval_mask; + unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */ + unsigned long opcode_mask; /* which bits define the opcode */ + enum microblaze_instr instr; + enum microblaze_instr_type instr_type; + /* more info about output format here */ +} opcodes[MAX_OPCODES] = + +{ + {"add", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst }, + {"rsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst }, + {"addc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst }, + {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst }, + {"addk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst }, + {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst }, + {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst }, + {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst }, + {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst }, + {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst }, + {"addi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst }, + {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst }, + {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst }, + {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst }, + {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst }, + {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst }, + {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst }, + {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst }, + {"mul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst }, + {"mulh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000001, OPCODE_MASK_H4, mulh, mult_inst }, + {"mulhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000003, OPCODE_MASK_H4, mulhu, mult_inst }, + {"mulhsu",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000002, OPCODE_MASK_H4, mulhsu, mult_inst }, + {"idiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst }, + {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst }, + {"bsll", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst }, + {"bsra", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst }, + {"bsrl", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst }, + {"get", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst }, + {"put", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst }, + {"nget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst }, + {"nput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst }, + {"cget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst }, + {"cput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst }, + {"ncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst }, + {"ncput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst }, + {"muli", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst }, + {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst }, + {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst }, + {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst }, + {"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst }, + {"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst }, + {"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst }, + {"andn", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst }, + {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst }, + {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst }, + {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst }, + {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst }, + {"sra", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst }, + {"src", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst }, + {"srl", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst }, + {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst }, + {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst }, + {"wic", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst }, + {"wdc", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst }, + {"wdc.clear", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000066, OPCODE_MASK_H34B, wdcclear, special_inst }, + {"wdc.flush", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000074, OPCODE_MASK_H34B, wdcflush, special_inst }, + {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst }, + {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst }, + {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst }, + {"brd", INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst }, + {"brld", INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst }, + {"bra", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst }, + {"brad", INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst }, + {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst }, + {"brk", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst }, + {"beq", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst }, + {"beqd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst }, + {"bne", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst }, + {"bned", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst }, + {"blt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst }, + {"bltd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst }, + {"ble", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst }, + {"bled", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst }, + {"bgt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst }, + {"bgtd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst }, + {"bge", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst }, + {"bged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst }, + {"ori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst }, + {"andi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst }, + {"xori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst }, + {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst }, + {"imm", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst }, + {"rtsd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst }, + {"rtid", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst }, + {"rtbd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst }, + {"rted", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst }, + {"bri", INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst }, + {"brid", INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst }, + {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst }, + {"brai", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst }, + {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst }, + {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst }, + {"brki", INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst }, + {"beqi", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst }, + {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst }, + {"bnei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst }, + {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst }, + {"blti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst }, + {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst }, + {"blei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst }, + {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst }, + {"bgti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst }, + {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst }, + {"bgei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst }, + {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst }, + {"lbu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst }, + {"lhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst }, + {"lw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst }, + {"lwx", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000400, OPCODE_MASK_H4, lwx, memory_load_inst }, + {"sb", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst }, + {"sh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst }, + {"sw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst }, + {"swx", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000400, OPCODE_MASK_H4, swx, memory_store_inst }, + {"lbui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst }, + {"lhui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst }, + {"lwi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst }, + {"sbi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst }, + {"shi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst }, + {"swi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst }, + {"nop", INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */ + {"la", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */ + {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */ + {"not", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */ + {"neg", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */ + {"rtb", INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */ + {"sub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */ + {"lmi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst }, + {"smi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst }, + {"msrset",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst }, + {"msrclr",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst }, + {"fadd", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst }, + {"frsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst }, + {"fmul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst }, + {"fdiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst }, + {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst }, + {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst }, + {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst }, + {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst }, + {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst }, + {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst }, + {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst }, + {"flt", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000280, OPCODE_MASK_H4, flt, arithmetic_inst }, + {"fint", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000300, OPCODE_MASK_H4, fint, arithmetic_inst }, + {"fsqrt", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000380, OPCODE_MASK_H4, fsqrt, arithmetic_inst }, + {"tget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001000, OPCODE_MASK_H32, tget, anyware_inst }, + {"tcget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003000, OPCODE_MASK_H32, tcget, anyware_inst }, + {"tnget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005000, OPCODE_MASK_H32, tnget, anyware_inst }, + {"tncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007000, OPCODE_MASK_H32, tncget, anyware_inst }, + {"tput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009000, OPCODE_MASK_H32, tput, anyware_inst }, + {"tcput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B000, OPCODE_MASK_H32, tcput, anyware_inst }, + {"tnput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D000, OPCODE_MASK_H32, tnput, anyware_inst }, + {"tncput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F000, OPCODE_MASK_H32, tncput, anyware_inst }, + + {"eget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000400, OPCODE_MASK_H32, eget, anyware_inst }, + {"ecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002400, OPCODE_MASK_H32, ecget, anyware_inst }, + {"neget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004400, OPCODE_MASK_H32, neget, anyware_inst }, + {"necget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006400, OPCODE_MASK_H32, necget, anyware_inst }, + {"eput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008400, OPCODE_MASK_H32, eput, anyware_inst }, + {"ecput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A400, OPCODE_MASK_H32, ecput, anyware_inst }, + {"neput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C400, OPCODE_MASK_H32, neput, anyware_inst }, + {"necput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E400, OPCODE_MASK_H32, necput, anyware_inst }, + + {"teget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001400, OPCODE_MASK_H32, teget, anyware_inst }, + {"tecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003400, OPCODE_MASK_H32, tecget, anyware_inst }, + {"tneget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005400, OPCODE_MASK_H32, tneget, anyware_inst }, + {"tnecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007400, OPCODE_MASK_H32, tnecget, anyware_inst }, + {"teput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009400, OPCODE_MASK_H32, teput, anyware_inst }, + {"tecput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B400, OPCODE_MASK_H32, tecput, anyware_inst }, + {"tneput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D400, OPCODE_MASK_H32, tneput, anyware_inst }, + {"tnecput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F400, OPCODE_MASK_H32, tnecput, anyware_inst }, + + {"aget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000800, OPCODE_MASK_H32, aget, anyware_inst }, + {"caget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002800, OPCODE_MASK_H32, caget, anyware_inst }, + {"naget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004800, OPCODE_MASK_H32, naget, anyware_inst }, + {"ncaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006800, OPCODE_MASK_H32, ncaget, anyware_inst }, + {"aput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008800, OPCODE_MASK_H32, aput, anyware_inst }, + {"caput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A800, OPCODE_MASK_H32, caput, anyware_inst }, + {"naput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C800, OPCODE_MASK_H32, naput, anyware_inst }, + {"ncaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E800, OPCODE_MASK_H32, ncaput, anyware_inst }, + + {"taget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001800, OPCODE_MASK_H32, taget, anyware_inst }, + {"tcaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003800, OPCODE_MASK_H32, tcaget, anyware_inst }, + {"tnaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005800, OPCODE_MASK_H32, tnaget, anyware_inst }, + {"tncaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007800, OPCODE_MASK_H32, tncaget, anyware_inst }, + {"taput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009800, OPCODE_MASK_H32, taput, anyware_inst }, + {"tcaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B800, OPCODE_MASK_H32, tcaput, anyware_inst }, + {"tnaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D800, OPCODE_MASK_H32, tnaput, anyware_inst }, + {"tncaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F800, OPCODE_MASK_H32, tncaput, anyware_inst }, + + {"eaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000C00, OPCODE_MASK_H32, eget, anyware_inst }, + {"ecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002C00, OPCODE_MASK_H32, ecget, anyware_inst }, + {"neaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004C00, OPCODE_MASK_H32, neget, anyware_inst }, + {"necaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006C00, OPCODE_MASK_H32, necget, anyware_inst }, + {"eaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008C00, OPCODE_MASK_H32, eput, anyware_inst }, + {"ecaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00AC00, OPCODE_MASK_H32, ecput, anyware_inst }, + {"neaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00CC00, OPCODE_MASK_H32, neput, anyware_inst }, + {"necaput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00EC00, OPCODE_MASK_H32, necput, anyware_inst }, + + {"teaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001C00, OPCODE_MASK_H32, teaget, anyware_inst }, + {"tecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003C00, OPCODE_MASK_H32, tecaget, anyware_inst }, + {"tneaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005C00, OPCODE_MASK_H32, tneaget, anyware_inst }, + {"tnecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007C00, OPCODE_MASK_H32, tnecaget, anyware_inst }, + {"teaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009C00, OPCODE_MASK_H32, teaput, anyware_inst }, + {"tecaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00BC00, OPCODE_MASK_H32, tecaput, anyware_inst }, + {"tneaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00DC00, OPCODE_MASK_H32, tneaput, anyware_inst }, + {"tnecaput", INST_TYPE_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00FC00, OPCODE_MASK_H32, tnecaput, anyware_inst }, + + {"getd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000000, OPCODE_MASK_H34C, getd, anyware_inst }, + {"tgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000080, OPCODE_MASK_H34C, tgetd, anyware_inst }, + {"cgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000100, OPCODE_MASK_H34C, cgetd, anyware_inst }, + {"tcgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000180, OPCODE_MASK_H34C, tcgetd, anyware_inst }, + {"ngetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000200, OPCODE_MASK_H34C, ngetd, anyware_inst }, + {"tngetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000280, OPCODE_MASK_H34C, tngetd, anyware_inst }, + {"ncgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000300, OPCODE_MASK_H34C, ncgetd, anyware_inst }, + {"tncgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000380, OPCODE_MASK_H34C, tncgetd, anyware_inst }, + {"putd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000400, OPCODE_MASK_H34C, putd, anyware_inst }, + {"tputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000480, OPCODE_MASK_H34C, tputd, anyware_inst }, + {"cputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000500, OPCODE_MASK_H34C, cputd, anyware_inst }, + {"tcputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000580, OPCODE_MASK_H34C, tcputd, anyware_inst }, + {"nputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000600, OPCODE_MASK_H34C, nputd, anyware_inst }, + {"tnputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000680, OPCODE_MASK_H34C, tnputd, anyware_inst }, + {"ncputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000700, OPCODE_MASK_H34C, ncputd, anyware_inst }, + {"tncputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000780, OPCODE_MASK_H34C, tncputd, anyware_inst }, + + {"egetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000020, OPCODE_MASK_H34C, egetd, anyware_inst }, + {"tegetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000A0, OPCODE_MASK_H34C, tegetd, anyware_inst }, + {"ecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000120, OPCODE_MASK_H34C, ecgetd, anyware_inst }, + {"tecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001A0, OPCODE_MASK_H34C, tecgetd, anyware_inst }, + {"negetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000220, OPCODE_MASK_H34C, negetd, anyware_inst }, + {"tnegetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002A0, OPCODE_MASK_H34C, tnegetd, anyware_inst }, + {"necgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000320, OPCODE_MASK_H34C, necgetd, anyware_inst }, + {"tnecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003A0, OPCODE_MASK_H34C, tnecgetd, anyware_inst }, + {"eputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000420, OPCODE_MASK_H34C, eputd, anyware_inst }, + {"teputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004A0, OPCODE_MASK_H34C, teputd, anyware_inst }, + {"ecputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000520, OPCODE_MASK_H34C, ecputd, anyware_inst }, + {"tecputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005A0, OPCODE_MASK_H34C, tecputd, anyware_inst }, + {"neputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000620, OPCODE_MASK_H34C, neputd, anyware_inst }, + {"tneputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006A0, OPCODE_MASK_H34C, tneputd, anyware_inst }, + {"necputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000720, OPCODE_MASK_H34C, necputd, anyware_inst }, + {"tnecputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007A0, OPCODE_MASK_H34C, tnecputd, anyware_inst }, + + {"agetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000040, OPCODE_MASK_H34C, agetd, anyware_inst }, + {"tagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000C0, OPCODE_MASK_H34C, tagetd, anyware_inst }, + {"cagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000140, OPCODE_MASK_H34C, cagetd, anyware_inst }, + {"tcagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001C0, OPCODE_MASK_H34C, tcagetd, anyware_inst }, + {"nagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000240, OPCODE_MASK_H34C, nagetd, anyware_inst }, + {"tnagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002C0, OPCODE_MASK_H34C, tnagetd, anyware_inst }, + {"ncagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000340, OPCODE_MASK_H34C, ncagetd, anyware_inst }, + {"tncagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003C0, OPCODE_MASK_H34C, tncagetd, anyware_inst }, + {"aputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000440, OPCODE_MASK_H34C, aputd, anyware_inst }, + {"taputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004C0, OPCODE_MASK_H34C, taputd, anyware_inst }, + {"caputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000540, OPCODE_MASK_H34C, caputd, anyware_inst }, + {"tcaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005C0, OPCODE_MASK_H34C, tcaputd, anyware_inst }, + {"naputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000640, OPCODE_MASK_H34C, naputd, anyware_inst }, + {"tnaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006C0, OPCODE_MASK_H34C, tnaputd, anyware_inst }, + {"ncaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000740, OPCODE_MASK_H34C, ncaputd, anyware_inst }, + {"tncaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007C0, OPCODE_MASK_H34C, tncaputd, anyware_inst }, + + {"eagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000060, OPCODE_MASK_H34C, eagetd, anyware_inst }, + {"teagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000E0, OPCODE_MASK_H34C, teagetd, anyware_inst }, + {"ecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000160, OPCODE_MASK_H34C, ecagetd, anyware_inst }, + {"tecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001E0, OPCODE_MASK_H34C, tecagetd, anyware_inst }, + {"neagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000260, OPCODE_MASK_H34C, neagetd, anyware_inst }, + {"tneagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002E0, OPCODE_MASK_H34C, tneagetd, anyware_inst }, + {"necagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000360, OPCODE_MASK_H34C, necagetd, anyware_inst }, + {"tnecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003E0, OPCODE_MASK_H34C, tnecagetd, anyware_inst }, + {"eaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000460, OPCODE_MASK_H34C, eaputd, anyware_inst }, + {"teaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004E0, OPCODE_MASK_H34C, teaputd, anyware_inst }, + {"ecaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000560, OPCODE_MASK_H34C, ecaputd, anyware_inst }, + {"tecaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005E0, OPCODE_MASK_H34C, tecaputd, anyware_inst }, + {"neaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000660, OPCODE_MASK_H34C, neaputd, anyware_inst }, + {"tneaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006E0, OPCODE_MASK_H34C, tneaputd, anyware_inst }, + {"necaputd", INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000760, OPCODE_MASK_H34C, necaputd, anyware_inst }, + {"tnecaputd", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007E0, OPCODE_MASK_H34C, tnecaputd, anyware_inst }, + {"", 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +/* prefix for register names */ +char register_prefix[] = "r"; +char special_register_prefix[] = "spr"; +char fsl_register_prefix[] = "rfsl"; +char pvr_register_prefix[] = "rpvr"; + + +/* #defines for valid immediate range */ +#define MIN_IMM ((int) 0x80000000) +#define MAX_IMM ((int) 0x7fffffff) + +#define MIN_IMM15 ((int) 0x0000) +#define MAX_IMM15 ((int) 0x7fff) + +#endif /* MICROBLAZE_OPC */ + +#include "dis-asm.h" +#include + +#define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW) +#define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW) +#define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW) +#define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW) +#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW) + +/* Local function prototypes. */ + +static char * get_field (long instr, long mask, unsigned short low); +static char * get_field_imm (long instr); +static char * get_field_imm5 (long instr); +static char * get_field_rfsl (long instr); +static char * get_field_imm15 (long instr); +#if 0 +static char * get_field_unsigned_imm (long instr); +#endif +char * get_field_special (long instr, struct op_code_struct * op); +unsigned long read_insn_microblaze (bfd_vma memaddr, + struct disassemble_info *info, + struct op_code_struct **opr); +enum microblaze_instr get_insn_microblaze (long inst, + bfd_boolean *isunsignedimm, + enum microblaze_instr_type *insn_type, + short *delay_slots); +short get_delay_slots_microblaze (long inst); +enum microblaze_instr microblaze_decode_insn (long insn, + int *rd, + int *ra, + int *rb, + int *imm); +unsigned long +microblaze_get_target_address (long inst, + bfd_boolean immfound, + int immval, + long pcval, + long r1val, + long r2val, + bfd_boolean *targetvalid, + bfd_boolean *unconditionalbranch); + +static char * +get_field (long instr, long mask, unsigned short low) +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm5 (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_rfsl (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & RFSL_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +static char * +get_field_imm15 (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +#if 0 +static char * +get_field_unsigned_imm (long instr) +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} +#endif + +/* + char * + get_field_special (instr) + long instr; + { + char tmpstr[25]; + + sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr"); + + return(strdup(tmpstr)); + } +*/ + +char * +get_field_special (long instr, struct op_code_struct * op) +{ + char tmpstr[25]; + char spr[6]; + + switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) { + + case REG_MSR_MASK : + strcpy(spr, "msr"); + break; + case REG_PC_MASK : + strcpy(spr, "pc"); + break; + case REG_EAR_MASK : + strcpy(spr, "ear"); + break; + case REG_ESR_MASK : + strcpy(spr, "esr"); + break; + case REG_FSR_MASK : + strcpy(spr, "fsr"); + break; + case REG_BTR_MASK : + strcpy(spr, "btr"); + break; + case REG_EDR_MASK : + strcpy(spr, "edr"); + break; + case REG_PID_MASK : + strcpy(spr, "pid"); + break; + case REG_ZPR_MASK : + strcpy(spr, "zpr"); + break; + case REG_TLBX_MASK : + strcpy(spr, "tlbx"); + break; + case REG_TLBLO_MASK : + strcpy(spr, "tlblo"); + break; + case REG_TLBHI_MASK : + strcpy(spr, "tlbhi"); + break; + case REG_TLBSX_MASK : + strcpy(spr, "tlbsx"); + break; + default : + { + if ( ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000) == REG_PVR_MASK) { + sprintf(tmpstr, "%spvr%d", register_prefix, (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ^ REG_PVR_MASK); + return(strdup(tmpstr)); + } else { + strcpy(spr, "pc"); + } + } + break; + } + + sprintf(tmpstr, "%s%s", register_prefix, spr); + return(strdup(tmpstr)); +} + +unsigned long +read_insn_microblaze (bfd_vma memaddr, + struct disassemble_info *info, + struct op_code_struct **opr) +{ + unsigned char ibytes[4]; + int status; + struct op_code_struct * op; + unsigned long inst; + + status = info->read_memory_func (memaddr, ibytes, 4, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return 0; + } + + if (info->endian == BFD_ENDIAN_BIG) + inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3]; + else if (info->endian == BFD_ENDIAN_LITTLE) + inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0]; + else + abort (); + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + *opr = op; + return inst; +} + + +int +print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) +{ + fprintf_ftype fprintf = info->fprintf_func; + void * stream = info->stream; + unsigned long inst, prev_inst; + struct op_code_struct * op, *pop; + int immval = 0; + bfd_boolean immfound = FALSE; + static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */ + static int prev_insn_vma = -1; /*init the prev insn vma */ + int curr_insn_vma = info->buffer_vma; + + info->bytes_per_chunk = 4; + + inst = read_insn_microblaze (memaddr, info, &op); + if (inst == 0) { + return -1; + } + + if (prev_insn_vma == curr_insn_vma) { + if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) { + prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop); + if (prev_inst == 0) + return -1; + if (pop->instr == imm) { + immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000; + immfound = TRUE; + } + else { + immval = 0; + immfound = FALSE; + } + } + } + /* make curr insn as prev insn */ + prev_insn_addr = memaddr; + prev_insn_vma = curr_insn_vma; + + if (op->name == 0) { + fprintf (stream, ".short 0x%04x", inst); + } + else + { + fprintf (stream, "%s", op->name); + + switch (op->inst_type) + { + case INST_TYPE_RD_R1_R2: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_R1_IMM: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst)); + if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_RD_R1_IMM5: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst)); + break; + case INST_TYPE_RD_RFSL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_rfsl(inst)); + break; + case INST_TYPE_R1_RFSL: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_rfsl(inst)); + break; + case INST_TYPE_RD_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op)); + break; + case INST_TYPE_SPECIAL_R1: + fprintf(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst)); + break; + case INST_TYPE_RD_R1: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst)); + break; + case INST_TYPE_R1_R2: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_R1_IMM: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst)); + /* The non-pc relative instructions are returns, which shouldn't + have a label printed */ + if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + immval += memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_IMM: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_IMM: + fprintf(stream, "\t%s", get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else if (op->inst_offset_type == INST_PC_OFFSET) { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_R2: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_R2: + fprintf(stream, "\t%s", get_field_r2(inst)); + break; + case INST_TYPE_R1: + fprintf(stream, "\t%s", get_field_r1(inst)); + break; + case INST_TYPE_RD_R1_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_IMM15: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm15(inst)); + break; + /* For tuqula instruction */ + case INST_TYPE_RD: + fprintf(stream, "\t%s", get_field_rd(inst)); + break; + case INST_TYPE_RFSL: + fprintf(stream, "\t%s", get_field_rfsl(inst)); + break; + default: + /* if the disassembler lags the instruction set */ + fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst); + break; + } + } + + /* Say how many bytes we consumed? */ + return 4; +} + +enum microblaze_instr +get_insn_microblaze (long inst, + bfd_boolean *isunsignedimm, + enum microblaze_instr_type *insn_type, + short *delay_slots) +{ + struct op_code_struct * op; + *isunsignedimm = FALSE; + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) + return invalid_inst; + else { + *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM); + *insn_type = op->instr_type; + *delay_slots = op->delay_slots; + return op->instr; + } +} + +short +get_delay_slots_microblaze (long inst) +{ + bfd_boolean isunsignedimm; + enum microblaze_instr_type insn_type; + enum microblaze_instr op; + short delay_slots; + + op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots); + if (op == invalid_inst) + return 0; + else + return delay_slots; +} + +enum microblaze_instr +microblaze_decode_insn (long insn, + int *rd, + int *ra, + int *rb, + int *imm) +{ + enum microblaze_instr op; + bfd_boolean t1; + enum microblaze_instr_type t2; + short t3; + + op = get_insn_microblaze(insn, &t1, &t2, &t3); + *rd = (insn & RD_MASK) >> RD_LOW; + *ra = (insn & RA_MASK) >> RA_LOW; + *rb = (insn & RB_MASK) >> RB_LOW; + t3 = (insn & IMM_MASK) >> IMM_LOW; + *imm = (int) t3; + return (op); +} + +unsigned long +microblaze_get_target_address (long inst, + bfd_boolean immfound, + int immval, + long pcval, + long r1val, + long r2val, + bfd_boolean *targetvalid, + bfd_boolean *unconditionalbranch) +{ + struct op_code_struct * op; + long targetaddr = 0; + + *unconditionalbranch = FALSE; + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) { + *targetvalid = FALSE; + } else if (op->instr_type == branch_inst) { + switch (op->inst_type) { + case INST_TYPE_R2: + *unconditionalbranch = TRUE; + /* fallthru */ + case INST_TYPE_RD_R2: + case INST_TYPE_R1_R2: + targetaddr = r2val; + *targetvalid = TRUE; + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + break; + case INST_TYPE_IMM: + *unconditionalbranch = TRUE; + /* fallthru */ + case INST_TYPE_RD_IMM: + case INST_TYPE_R1_IMM: + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + *targetvalid = TRUE; + break; + default: + *targetvalid = FALSE; + break; + } + } else if (op->instr_type == return_inst) { + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + targetaddr += r1val; + *targetvalid = TRUE; + } else { + *targetvalid = FALSE; + } + return targetaddr; +} diff --git a/qemu/qemu-git/mips-dis.c b/qemu/qemu-git/mips-dis.c new file mode 100644 index 0000000..169169c --- /dev/null +++ b/qemu/qemu-git/mips-dis.c @@ -0,0 +1,4842 @@ +/* Print mips instructions for GDB, the GNU debugger, or for objdump. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). + +This file is part of GDB, GAS, and the GNU binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . */ + +#include "dis-asm.h" + +/* mips.h. Mips opcode list for GDB, the GNU debugger. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Ralph Campbell and OSF + Commented and modified by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). An optional two-operand form of break/sdbbp + allows the lower ten bits to be set too, and MIPS32 and later + architectures allow 20 bits to be set with a signal operand + (using CODE20). + + The syscall instruction uses CODE20. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_CODE2 0x3ff +#define OP_SH_CODE2 6 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */ +#define OP_SH_CODE20 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 +#define OP_SH_LOCC 8 /* FP condition code. */ +#define OP_SH_HICC 18 /* FP condition code. */ +#define OP_MASK_CC 0x7 +#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */ +#define OP_MASK_COP1NORM 0x1 /* a single bit. */ +#define OP_SH_COP1SPEC 21 /* COP1 encodings. */ +#define OP_MASK_COP1SPEC 0xf +#define OP_MASK_COP1SCLR 0x4 +#define OP_MASK_COP1CMP 0x3 +#define OP_SH_COP1CMP 4 +#define OP_SH_FORMAT 21 /* FP short format field. */ +#define OP_MASK_FORMAT 0x7 +#define OP_SH_TRUE 16 +#define OP_MASK_TRUE 0x1 +#define OP_SH_GE 17 +#define OP_MASK_GE 0x01 +#define OP_SH_UNSIGNED 16 +#define OP_MASK_UNSIGNED 0x1 +#define OP_SH_HINT 16 +#define OP_MASK_HINT 0x1f +#define OP_SH_MMI 0 /* Multimedia (parallel) op. */ +#define OP_MASK_MMI 0x3f +#define OP_SH_MMISUB 6 +#define OP_MASK_MMISUB 0x1f +#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */ +#define OP_SH_PERFREG 1 +#define OP_SH_SEL 0 /* Coprocessor select field. */ +#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */ +#define OP_SH_CODE19 6 /* 19 bit wait code. */ +#define OP_MASK_CODE19 0x7ffff +#define OP_SH_ALN 21 +#define OP_MASK_ALN 0x7 +#define OP_SH_VSEL 21 +#define OP_MASK_VSEL 0x1f +#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits, + but 0x8-0xf don't select bytes. */ +#define OP_SH_VECBYTE 22 +#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */ +#define OP_SH_VECALIGN 21 +#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */ +#define OP_SH_INSMSB 11 +#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */ +#define OP_SH_EXTMSBD 11 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* MIPS DSP ASE */ +#define OP_SH_DSPACC 11 +#define OP_MASK_DSPACC 0x3 +#define OP_SH_DSPACC_S 21 +#define OP_MASK_DSPACC_S 0x3 +#define OP_SH_DSPSFT 20 +#define OP_MASK_DSPSFT 0x3f +#define OP_SH_DSPSFT_7 19 +#define OP_MASK_DSPSFT_7 0x7f +#define OP_SH_SA3 21 +#define OP_MASK_SA3 0x7 +#define OP_SH_SA4 21 +#define OP_MASK_SA4 0xf +#define OP_SH_IMM8 16 +#define OP_MASK_IMM8 0xff +#define OP_SH_IMM10 16 +#define OP_MASK_IMM10 0x3ff +#define OP_SH_WRDSP 11 +#define OP_MASK_WRDSP 0x3f +#define OP_SH_RDDSP 16 +#define OP_MASK_RDDSP 0x3f +#define OP_SH_BP 11 +#define OP_MASK_BP 0x3 + +/* MIPS MT ASE */ +#define OP_SH_MT_U 5 +#define OP_MASK_MT_U 0x1 +#define OP_SH_MT_H 4 +#define OP_MASK_MT_H 0x1 +#define OP_SH_MTACC_T 18 +#define OP_MASK_MTACC_T 0x3 +#define OP_SH_MTACC_D 13 +#define OP_MASK_MTACC_D 0x3 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* Values in the 'VSEL' field. */ +#define MDMX_FMTSEL_IMM_QH 0x1d +#define MDMX_FMTSEL_IMM_OB 0x1e +#define MDMX_FMTSEL_VEC_QH 0x15 +#define MDMX_FMTSEL_VEC_OB 0x16 + +/* UDI */ +#define OP_SH_UDI1 6 +#define OP_MASK_UDI1 0x1f +#define OP_SH_UDI2 6 +#define OP_MASK_UDI2 0x3ff +#define OP_SH_UDI3 6 +#define OP_MASK_UDI3 0x7fff +#define OP_SH_UDI4 6 +#define OP_MASK_UDI4 0xfffff +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is 0. */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned long pinfo2; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned long membership; +}; + +/* These are the characters which may appear in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + Also used for immediate operands in vr5400 vector insns. + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "q" 10 bit extra breakpoint code (OP_*_CODE2) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "U" 5 bit same destination register in both OP_*_RD and OP_*_RT + (used by clo and clz) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall/breakpoint function code (OP_*_CODE20) + "J" 19 bit wait function code (OP_*_CODE19) + "x" accept and ignore register name + "z" must be zero register + "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) + "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes + LSB (OP_*_SHAMT). + Enforces: 0 <= pos < 32. + "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + (Also used by "dext" w/ different limits, but limits for + that are checked by the M_DEXT macro.) + "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT). + Enforces: 32 <= pos < 64. + "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL) + "P" 5 bit performance-monitor register (OP_*_PERFREG) + "e" 5 bit vector register byte specifier (OP_*_VECBYTE) + "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN) + see also "k" above + "+D" Combined destination register ("G") and sel ("H") for CP0 ops, + for pretty-printing in disassembly only. + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate (value placed in imm_expr). + "+I" 32 bit immediate (value placed in imm2_expr). + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 + + MDMX instruction operands (note that while these use the FP register + fields, they accept both $fN and $vN names for the registers): + "O" MDMX alignment offset (OP_*_ALN) + "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) + "X" MDMX destination register (OP_*_FD) + "Y" MDMX source register (OP_*_FS) + "Z" MDMX source register (OP_*_FT) + + DSP ASE usage: + "2" 2 bit unsigned immediate for byte align (OP_*_BP) + "3" 3 bit unsigned immediate (OP_*_SA3) + "4" 4 bit unsigned immediate (OP_*_SA4) + "5" 8 bit unsigned immediate (OP_*_IMM8) + "6" 5 bit unsigned immediate (OP_*_RS) + "7" 2 bit dsp accumulator register (OP_*_DSPACC) + "8" 6 bit unsigned immediate (OP_*_WRDSP) + "9" 2 bit dsp accumulator register (OP_*_DSPACC_S) + "0" 6 bit signed immediate (OP_*_DSPSFT) + ":" 7 bit signed immediate (OP_*_DSPSFT_7) + "'" 6 bit unsigned immediate (OP_*_RDDSP) + "@" 10 bit signed immediate (OP_*_IMM10) + + MT ASE usage: + "!" 1 bit usermode flag (OP_*_MT_U) + "$" 1 bit load high flag (OP_*_MT_H) + "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T) + "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D) + "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD) + "+t" 5 bit coprocessor 0 destination register (OP_*_RT) + "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only + + UDI immediates: + "+1" UDI immediate bits 6-10 + "+2" UDI immediate bits 6-15 + "+3" UDI immediate bits 6-20 + "+4" UDI immediate bits 6-25 + + Other: + "()" parens surrounding optional value + "," separates operands + "[]" brackets around index for vector-op scalar operand specifier (vr5400) + "+" Start of extension sequence. + + Characters used so far, for quick reference when adding more: + "234567890" + "%[]<>(),+:'@!$*&" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklopqrstuvwxz" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "1234" + "ABCDEFGHIT" + "t" +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* Instruction uses single precision floating point. */ +#define FP_S 0x10000000 +/* Instruction uses double precision floating point. */ +#define FP_D 0x20000000 +/* Instruction is part of the tx39's integer multiply family. */ +#define INSN_MULT 0x40000000 +/* Instruction synchronize shared memory. */ +#define INSN_SYNC 0x80000000 + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Instruction reads MDMX accumulator. */ +#define INSN2_READ_MDMX_ACC 0x00000002 +/* Instruction writes MDMX accumulator. */ +#define INSN2_WRITE_MDMX_ACC 0x00000004 + +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. ISAs, as defined below, are logical + ORs of these bits, indicating that they support the instructions + defined at the given level. */ + +#define INSN_ISA_MASK 0x00000fff +#define INSN_ISA1 0x00000001 +#define INSN_ISA2 0x00000002 +#define INSN_ISA3 0x00000004 +#define INSN_ISA4 0x00000008 +#define INSN_ISA5 0x00000010 +#define INSN_ISA32 0x00000020 +#define INSN_ISA64 0x00000040 +#define INSN_ISA32R2 0x00000080 +#define INSN_ISA64R2 0x00000100 + +/* Masks used for MIPS-defined ASEs. */ +#define INSN_ASE_MASK 0x0000f000 + +/* DSP ASE */ +#define INSN_DSP 0x00001000 +#define INSN_DSP64 0x00002000 +/* MIPS 16 ASE */ +#define INSN_MIPS16 0x00004000 +/* MIPS-3D ASE */ +#define INSN_MIPS3D 0x00008000 + +/* Chip specific instructions. These are bitmasks. */ + +/* MIPS R4650 instruction. */ +#define INSN_4650 0x00010000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x00020000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x00040000 +/* Toshiba R3900 instruction. */ +#define INSN_3900 0x00080000 +/* MIPS R10000 instruction. */ +#define INSN_10000 0x00100000 +/* Broadcom SB-1 instruction. */ +#define INSN_SB1 0x00200000 +/* NEC VR4111/VR4181 instruction. */ +#define INSN_4111 0x00400000 +/* NEC VR4120 instruction. */ +#define INSN_4120 0x00800000 +/* NEC VR5400 instruction. */ +#define INSN_5400 0x01000000 +/* NEC VR5500 instruction. */ +#define INSN_5500 0x02000000 + +/* MDMX ASE */ +#define INSN_MDMX 0x04000000 +/* MT ASE */ +#define INSN_MT 0x08000000 +/* SmartMIPS ASE */ +#define INSN_SMARTMIPS 0x10000000 +/* DSP R2 ASE */ +#define INSN_DSPR2 0x20000000 + +/* MIPS ISA defines, use instead of hardcoding ISA level. */ + +#define ISA_UNKNOWN 0 /* Gas internal use. */ +#define ISA_MIPS1 (INSN_ISA1) +#define ISA_MIPS2 (ISA_MIPS1 | INSN_ISA2) +#define ISA_MIPS3 (ISA_MIPS2 | INSN_ISA3) +#define ISA_MIPS4 (ISA_MIPS3 | INSN_ISA4) +#define ISA_MIPS5 (ISA_MIPS4 | INSN_ISA5) + +#define ISA_MIPS32 (ISA_MIPS2 | INSN_ISA32) +#define ISA_MIPS64 (ISA_MIPS5 | INSN_ISA32 | INSN_ISA64) + +#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2) +#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2) + + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ +#define CPU_R3000 3000 +#define CPU_R3900 3900 +#define CPU_R4000 4000 +#define CPU_R4010 4010 +#define CPU_VR4100 4100 +#define CPU_R4111 4111 +#define CPU_VR4120 4120 +#define CPU_R4300 4300 +#define CPU_R4400 4400 +#define CPU_R4600 4600 +#define CPU_R4650 4650 +#define CPU_R5000 5000 +#define CPU_VR5400 5400 +#define CPU_VR5500 5500 +#define CPU_R6000 6000 +#define CPU_RM7000 7000 +#define CPU_R8000 8000 +#define CPU_R10000 10000 +#define CPU_R12000 12000 +#define CPU_MIPS16 16 +#define CPU_MIPS32 32 +#define CPU_MIPS32R2 33 +#define CPU_MIPS5 5 +#define CPU_MIPS64 64 +#define CPU_MIPS64R2 65 +#define CPU_SB1 12310201 /* octal 'SB', 01. */ + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. */ + +#if 0 +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (((insn)->membership & isa) != 0 \ + || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ + || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ + || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ + || ((cpu == CPU_R10000 || cpu == CPU_R12000) \ + && ((insn)->membership & INSN_10000) != 0) \ + || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \ + || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \ + || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \ + || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ + || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ + || 0) /* Please keep this term for easier source merging. */ +#else +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (1 != 0) +#endif + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means address + _AB appended means address with base register + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BALIGN, + M_BEQ, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE, + M_BNE_I, + M_BNEL_I, + M_CACHE_AB, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DEXT, + M_DINS, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLCA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_DSUBU_I_2, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LCA_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MOVE, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_DROR, + M_ROR, + M_DROR_I, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_SUBU_I_2, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I, + M_COP0, + M_COP1, + M_COP2, + M_COP3, + M_NUM_MACROS +}; + + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +extern const struct mips_opcode mips_builtin_opcodes[]; +extern const int bfd_mips_num_builtin_opcodes; +extern struct mips_opcode *mips_opcodes; +extern int bfd_mips_num_opcodes; +#define NUMOPCODES bfd_mips_num_opcodes + + +/* The rest of this file adds definitions for the mips16 TinyRISC + processor. */ + +/* These are the bitmasks and shift counts used for the different + fields in the instruction formats. Other than OP, no masks are + provided for the fixed portions of an instruction, since they are + not needed. + + The I format uses IMM11. + + The RI format uses RX and IMM8. + + The RR format uses RX, and RY. + + The RRI format uses RX, RY, and IMM5. + + The RRR format uses RX, RY, and RZ. + + The RRI_A format uses RX, RY, and IMM4. + + The SHIFT format uses RX, RY, and SHAMT. + + The I8 format uses IMM8. + + The I8_MOVR32 format uses RY and REGR32. + + The IR_MOV32R format uses REG32R and MOV32Z. + + The I64 format uses IMM8. + + The RI64 format uses RY and IMM5. + */ + +#define MIPS16OP_MASK_OP 0x1f +#define MIPS16OP_SH_OP 11 +#define MIPS16OP_MASK_IMM11 0x7ff +#define MIPS16OP_SH_IMM11 0 +#define MIPS16OP_MASK_RX 0x7 +#define MIPS16OP_SH_RX 8 +#define MIPS16OP_MASK_IMM8 0xff +#define MIPS16OP_SH_IMM8 0 +#define MIPS16OP_MASK_RY 0x7 +#define MIPS16OP_SH_RY 5 +#define MIPS16OP_MASK_IMM5 0x1f +#define MIPS16OP_SH_IMM5 0 +#define MIPS16OP_MASK_RZ 0x7 +#define MIPS16OP_SH_RZ 2 +#define MIPS16OP_MASK_IMM4 0xf +#define MIPS16OP_SH_IMM4 0 +#define MIPS16OP_MASK_REGR32 0x1f +#define MIPS16OP_SH_REGR32 0 +#define MIPS16OP_MASK_REG32R 0x1f +#define MIPS16OP_SH_REG32R 3 +#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18)) +#define MIPS16OP_MASK_MOVE32Z 0x7 +#define MIPS16OP_SH_MOVE32Z 0 +#define MIPS16OP_MASK_IMM6 0x3f +#define MIPS16OP_SH_IMM6 5 + +/* These are the characters which may appears in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + "y" 3 bit register (MIPS16OP_*_RY) + "x" 3 bit register (MIPS16OP_*_RX) + "z" 3 bit register (MIPS16OP_*_RZ) + "Z" 3 bit register (MIPS16OP_*_MOVE32Z) + "v" 3 bit same register as source and destination (MIPS16OP_*_RX) + "w" 3 bit same register as source and destination (MIPS16OP_*_RY) + "0" zero register ($0) + "S" stack pointer ($sp or $29) + "P" program counter + "R" return address register ($ra or $31) + "X" 5 bit MIPS register (MIPS16OP_*_REGR32) + "Y" 5 bit MIPS register (MIPS16OP_*_REG32R) + "6" 6 bit unsigned break code (MIPS16OP_*_IMM6) + "a" 26 bit jump address + "e" 11 bit extension value + "l" register list for entry instruction + "L" register list for exit instruction + + The remaining codes may be extended. Except as otherwise noted, + the full extended operand is a 16 bit signed value. + "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned) + ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned) + "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned) + "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned) + "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed) + "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5) + "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5) + "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5) + "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5) + "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5) + "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) + "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8) + "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8) + "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned) + "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8) + "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8) + "p" 8 bit conditional branch address (MIPS16OP_*_IMM8) + "q" 11 bit branch address (MIPS16OP_*_IMM11) + "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8) + "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5) + "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) + */ + +/* Save/restore encoding for the args field when all 4 registers are + either saved as arguments or saved/restored as statics. */ +#define MIPS16_ALL_ARGS 0xe +#define MIPS16_ALL_STATICS 0xb + +/* For the mips16, we use the same opcode table format and a few of + the same flags. However, most of the flags are different. */ + +/* Modifies the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_WRITE_X 0x00000001 +/* Modifies the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_WRITE_Y 0x00000002 +/* Modifies the register in MIPS16OP_*_RZ. */ +#define MIPS16_INSN_WRITE_Z 0x00000004 +/* Modifies the T ($24) register. */ +#define MIPS16_INSN_WRITE_T 0x00000008 +/* Modifies the SP ($29) register. */ +#define MIPS16_INSN_WRITE_SP 0x00000010 +/* Modifies the RA ($31) register. */ +#define MIPS16_INSN_WRITE_31 0x00000020 +/* Modifies the general purpose register in MIPS16OP_*_REG32R. */ +#define MIPS16_INSN_WRITE_GPR_Y 0x00000040 +/* Reads the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_READ_X 0x00000080 +/* Reads the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_READ_Y 0x00000100 +/* Reads the register in MIPS16OP_*_MOVE32Z. */ +#define MIPS16_INSN_READ_Z 0x00000200 +/* Reads the T ($24) register. */ +#define MIPS16_INSN_READ_T 0x00000400 +/* Reads the SP ($29) register. */ +#define MIPS16_INSN_READ_SP 0x00000800 +/* Reads the RA ($31) register. */ +#define MIPS16_INSN_READ_31 0x00001000 +/* Reads the program counter. */ +#define MIPS16_INSN_READ_PC 0x00002000 +/* Reads the general purpose register in MIPS16OP_*_REGR32. */ +#define MIPS16_INSN_READ_GPR_X 0x00004000 +/* Is a branch insn. */ +#define MIPS16_INSN_BRANCH 0x00010000 + +/* The following flags have the same value for the mips16 opcode + table: + INSN_UNCOND_BRANCH_DELAY + INSN_COND_BRANCH_DELAY + INSN_COND_BRANCH_LIKELY (never used) + INSN_READ_HI + INSN_READ_LO + INSN_WRITE_HI + INSN_WRITE_LO + INSN_TRAP + INSN_ISA3 + */ + +extern const struct mips_opcode mips16_opcodes[]; +extern const int bfd_mips16_num_opcodes; + +/* Short hand so the lines aren't too long. */ + +#define LDD INSN_LOAD_MEMORY_DELAY +#define LCD INSN_LOAD_COPROC_DELAY +#define UBD INSN_UNCOND_BRANCH_DELAY +#define CBD INSN_COND_BRANCH_DELAY +#define COD INSN_COPROC_MOVE_DELAY +#define CLD INSN_COPROC_MEMORY_DELAY +#define CBL INSN_COND_BRANCH_LIKELY +#define TRAP INSN_TRAP +#define SM INSN_STORE_MEMORY + +#define WR_d INSN_WRITE_GPR_D +#define WR_t INSN_WRITE_GPR_T +#define WR_31 INSN_WRITE_GPR_31 +#define WR_D INSN_WRITE_FPR_D +#define WR_T INSN_WRITE_FPR_T +#define WR_S INSN_WRITE_FPR_S +#define RD_s INSN_READ_GPR_S +#define RD_b INSN_READ_GPR_S +#define RD_t INSN_READ_GPR_T +#define RD_S INSN_READ_FPR_S +#define RD_T INSN_READ_FPR_T +#define RD_R INSN_READ_FPR_R +#define WR_CC INSN_WRITE_COND_CODE +#define RD_CC INSN_READ_COND_CODE +#define RD_C0 INSN_COP +#define RD_C1 INSN_COP +#define RD_C2 INSN_COP +#define RD_C3 INSN_COP +#define WR_C0 INSN_COP +#define WR_C1 INSN_COP +#define WR_C2 INSN_COP +#define WR_C3 INSN_COP + +#define WR_HI INSN_WRITE_HI +#define RD_HI INSN_READ_HI +#define MOD_HI WR_HI|RD_HI + +#define WR_LO INSN_WRITE_LO +#define RD_LO INSN_READ_LO +#define MOD_LO WR_LO|RD_LO + +#define WR_HILO WR_HI|WR_LO +#define RD_HILO RD_HI|RD_LO +#define MOD_HILO WR_HILO|RD_HILO + +#define IS_M INSN_MULT + +#define WR_MACC INSN2_WRITE_MDMX_ACC +#define RD_MACC INSN2_READ_MDMX_ACC + +#define I1 INSN_ISA1 +#define I2 INSN_ISA2 +#define I3 INSN_ISA3 +#define I4 INSN_ISA4 +#define I5 INSN_ISA5 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define I33 INSN_ISA32R2 +#define I65 INSN_ISA64R2 + +/* MIPS64 MIPS-3D ASE support. */ +#define I16 INSN_MIPS16 + +/* MIPS32 SmartMIPS ASE support. */ +#define SMT INSN_SMARTMIPS + +/* MIPS64 MIPS-3D ASE support. */ +#define M3D INSN_MIPS3D + +/* MIPS64 MDMX ASE support. */ +#define MX INSN_MDMX + +#define P3 INSN_4650 +#define L1 INSN_4010 +#define V1 (INSN_4100 | INSN_4111 | INSN_4120) +#define T3 INSN_3900 +#define M1 INSN_10000 +#define SB1 INSN_SB1 +#define N411 INSN_4111 +#define N412 INSN_4120 +#define N5 (INSN_5400 | INSN_5500) +#define N54 INSN_5400 +#define N55 INSN_5500 + +#define G1 (T3 \ + ) + +#define G2 (T3 \ + ) + +#define G3 (I4 \ + ) + +/* MIPS DSP ASE support. + NOTE: + 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair + of original HI and LO. $ac1, $ac2 and $ac3 are new registers, and have + the same structure as $ac0 (HI + LO). For DSP instructions that write or + read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a + (RD_HILO) attributes, such that HILO dependencies are maintained + conservatively. + + 2. For some mul. instructions that use integer registers as destinations + but destroy HI+LO as side-effect, we add WR_HILO to their attributes. + + 3. MIPS DSP ASE includes a new DSP control register, which has 6 fields + (ccond, outflag, EFI, c, scount, pos). Many DSP instructions read or write + certain fields of the DSP control register. For simplicity, we decide not + to track dependencies of these fields. + However, "bposge32" is a branch instruction that depends on the "pos" + field. In order to make sure that GAS does not reorder DSP instructions + that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP) + attribute to those instructions that write the "pos" field. */ + +#define WR_a WR_HILO /* Write dsp accumulators (reuse WR_HILO) */ +#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */ +#define MOD_a WR_a|RD_a +#define DSP_VOLA INSN_TRAP +#define D32 INSN_DSP +#define D33 INSN_DSPR2 +#define D64 INSN_DSP64 + +/* MIPS MT ASE support. */ +#define MT32 INSN_MT + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Because of the lookup algorithm used, entries with the same opcode + name must be contiguous. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +const struct mips_opcode mips_builtin_opcodes[] = +{ +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, args, match, mask, pinfo, membership */ +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, +{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, INSN2_ALIAS, I32|N55 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, INSN2_ALIAS, I33 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* ori */ +{"li", "t,I", 0, (int) M_LI, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, INSN2_ALIAS, I1 },/* bgezal 0*/ + +{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I1 }, +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, I1 }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, 0, I1 }, +{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, 0, N54 }, +{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX|SB1 }, +{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, 0, I1 }, +{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +/* b is at the top of the table. */ +/* bal is at the top of the table. */ +/* bc0[tf]l? are at the bottom of the table. */ +{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, +/* bc2* are at the bottom of the table. */ +/* bc3* are at the bottom of the table. */ +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, 0, I2|T3 }, +{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, 0, I1 }, +{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1 }, +{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, 0, I2|T3 }, +{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, 0, I2|T3 }, +{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1 }, +{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I1 }, +{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, 0, I2|T3 }, +{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, 0, I1 }, +{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I1 }, +{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, 0, I2|T3 }, +{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, 0, I1 }, +{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I1 }, +{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, 0, I2|T3 }, +{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, 0, I1 }, +{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I1 }, +{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, 0, I2|T3 }, +{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, 0, I2|T3 }, +{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, 0, I1 }, +{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I1 }, +{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, 0, I2|T3 }, +{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, 0, I2|T3 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, 0, I1 }, +{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I1 }, +{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, 0, I2|T3 }, +{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, 0, I2|T3 }, +{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, 0, I1 }, +{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1 }, +{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, 0, I2|T3 }, +{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, 0, I2|T3 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, 0, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, 0, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, 0, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +/* CW4010 instructions which are aliases for the cache instruction. */ +{"flushi", "", 0xbc010000, 0xffffffff, 0, 0, L1 }, +{"flushd", "", 0xbc020000, 0xffffffff, 0, 0, L1 }, +{"flushid", "", 0xbc030000, 0xffffffff, 0, 0, L1 }, +{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, 0, L1 }, +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, 0, I3|I32|T3}, +{"cache", "k,A(b)", 0, (int) M_CACHE_AB, INSN_MACRO, 0, I3|I32|T3}, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +/* cfc2 is at the bottom of the table. */ +/* cfc3 is at the bottom of the table. */ +{"cftc1", "d,E", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc1", "d,T", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc2", "d,E", 0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +/* ctc2 is at the bottom of the table. */ +/* ctc3 is at the bottom of the table. */ +{"cttc1", "t,g", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc1", "t,S", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc2", "t,g", 0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC, 0, MT32 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_S|FP_D, 0, I5|I33 }, +{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, 0, I3 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, 0, I3 }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, 0, I3 }, +{"dbreak", "", 0x7000003f, 0xffffffff, 0, 0, N5 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +/* dctr and dctw are used on the r5000. */ +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, 0, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, 0, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, 0, I32|G2 }, +{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, 0, I65 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* For ddiv, see the comments about div. */ +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, 0, I3 }, +{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, 0, I3 }, +/* For ddivu, see the comments about div. */ +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I3 }, +{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, 0, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, 0, I65 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* The MIPS assembler treats the div opcode with two operands as + though the first operand appeared twice (the first operand is both + a source and a destination). To get the div machine instruction, + you must use an explicit destination of $0. */ +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, 0, I1 }, +{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, 0, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +/* For divu, see the comments about div. */ +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1 }, +{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, 0, I1 }, +{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, 0, I3 }, +{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, 0, I3 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, 0, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, 0, I3 }, /* ori */ +{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, 0, I3 }, +{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, 0, N411 }, +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I3 }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmt", "", 0x41600bc1, 0xffffffff, TRAP, 0, MT32 }, +{"dmt", "t", 0x41600bc1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3 }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +/* dmfc2 is at the bottom of the table. */ +/* dmtc2 is at the bottom of the table. */ +/* dmfc3 is at the bottom of the table. */ +/* dmtc3 is at the bottom of the table. */ +{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, 0, I3 }, +{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, 0, I3 }, +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsubu 0*/ +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, 0, I3 }, +{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, 0, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, 0, I3 }, +{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, 0, I3 }, +{"dret", "", 0x7000003e, 0xffffffff, 0, 0, N5 }, +{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I3 }, +{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I3 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I3 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I3 }, +{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I65 }, +{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I65 }, +{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I65 }, +{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, 0, I3 }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I3 }, +{"dvpe", "", 0x41600001, 0xffffffff, TRAP, 0, MT32 }, +{"dvpe", "t", 0x41600001, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, +{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 }, +{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, +{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"hibernate","", 0x42000023, 0xffffffff, 0, 0, V1 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, +/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with + the same hazard barrier effect. */ +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, 0, I32 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, /* jr */ +/* SVR4 PIC code requires special handling for j, so it must be a + macro. */ +{"j", "a", 0, (int) M_J_A, INSN_MACRO, 0, I1 }, +/* This form of j is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"j", "a", 0x08000000, 0xfc000000, UBD, 0, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, 0, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I1 }, +/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr + with the same hazard barrier effect. */ +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, 0, I32 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I32 }, +/* SVR4 PIC code requires special handling for jal, so it must be a + macro. */ +{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, 0, I1 }, +{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, 0, I1 }, +{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, 0, I1 }, +/* This form of jal is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, 0, I16 }, +{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, 0, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, 0, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, 0, I1 }, +{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, 0, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, 0, I3 }, +{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, 0, I1 }, +{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, 0, I1 }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, /* ldc1 */ +{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, 0, I1 }, +{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, 0, I1 }, +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, 0, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, 0, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, 0, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, 0, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, 0, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, 0, I1 }, +/* li is at the start of the table. */ +{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, 0, I1 }, +{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, 0, I1 }, +{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, 0, I1 }, +{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, 0, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, +{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, 0, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, /* lwc1 */ +{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, 0, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I2 }, /* as lwl */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I2 }, /* as lwr */ +{"fork", "d,s,t", 0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t, 0, MT32 }, +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, LDD|RD_b|RD_t|WR_d, 0, SMT }, +{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"madd", "7,s,t", 0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"maddp", "s,t", 0x70000441, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"maddu", "7,s,t", 0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, N411 }, +{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mftacx", "d", 0x41020021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftacx", "d,*", 0x41020021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftc0", "d,+t", 0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,+T", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,E,H", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc1", "d,T", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc1", "d,E", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc2", "d,E", 0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mftdsp", "d", 0x41100021, 0xffff07ff, TRAP|WR_d, 0, MT32 }, +{"mftgpr", "d,t", 0x41000020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mfthc1", "d,T", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc1", "d,E", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc2", "d,E", 0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mfthi", "d", 0x41010021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mfthi", "d,*", 0x41010021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d", 0x41000021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d,*", 0x41000021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftr", "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d, 0, MT32 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +/* mfc2 is at the bottom of the table. */ +/* mfhc2 is at the bottom of the table. */ +/* mfc3 is at the bottom of the table. */ +{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, 0, N5 }, +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, 0, I1 }, +{"mfhi", "d,9", 0x00000010, 0xff9f07ff, WR_d|RD_HI, 0, D32 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, 0, I1 }, +{"mflo", "d,9", 0x00000012, 0xff9f07ff, WR_d|RD_LO, 0, D32 }, +{"mflhxu", "d", 0x00000052, 0xffff07ff, WR_d|MOD_HILO, 0, SMT }, +{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +/* move is at the top of the table. */ +{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msub", "7,s,t", 0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msubu", "7,s,t", 0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I1 }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +/* mtc2 is at the bottom of the table. */ +/* mthc2 is at the bottom of the table. */ +/* mtc3 is at the bottom of the table. */ +{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, 0, N5 }, +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, 0, I1 }, +{"mthi", "s,7", 0x00000011, 0xfc1fe7ff, RD_s|WR_HI, 0, D32 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, 0, I1 }, +{"mtlo", "s,7", 0x00000013, 0xfc1fe7ff, RD_s|WR_LO, 0, D32 }, +{"mtlhx", "s", 0x00000053, 0xfc1fffff, RD_s|MOD_HILO, 0, SMT }, +{"mttc0", "t,G", 0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,+D", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,G,H", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc1", "t,S", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc1", "t,G", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc2", "t,g", 0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mttacx", "t", 0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttacx", "t,&", 0x41801021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttdsp", "t", 0x41808021, 0xffe0ffff, TRAP|RD_t, 0, MT32 }, +{"mttgpr", "t,d", 0x41800020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mtthc1", "t,S", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc1", "t,G", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc2", "t,g", 0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mtthi", "t", 0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mtthi", "t,&", 0x41800821, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t", 0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t,&", 0x41800021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttr", "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t, 0, MT32 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, I32|P3|N55}, +{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N54 }, +{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, 0, I1 }, +{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, 0, I1 }, +{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, 0, I1 }, +{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, 0, I1 }, +{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"mult", "7,s,t", 0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"multp", "s,t", 0x00000459, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"multu", "7,s,t", 0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +/* nop is at the start of the table. */ +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, 0, I1 }, +{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, 0, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, 0, I1 }, +{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, SB1 }, +{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, + /* pref and prefx are at the start of the table. */ +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"pperm", "s,t", 0x70000481, 0xfc00ffff, MOD_HILO|RD_s|RD_t, 0, SMT }, +{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, 0, N54 }, +{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, 0, N54 }, +{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, 0, N54 }, +{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, 0, I1 }, +{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, 0, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, 0, I1 }, +{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, 0, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, 0, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, 0, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, 0, I1|T3 }, +{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I1 }, +{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I1 }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I1 }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, 0, N5|I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I33|SMT }, +{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I33|SMT }, +{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I33|SMT }, +{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I33|SMT }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, 0, N54 }, +{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, 0, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I2 }, +{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, 0, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I3 }, +{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, 0, I3 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, 0, I1 }, +{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, 0, I1 }, +{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, 0, G2 }, +{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, 0, G2 }, +{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, 0, G2 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, 0, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, 0, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I2 }, +{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, 0, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, 0, I2 }, +{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, 0, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, 0, I1 }, +{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, 0, I1 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, 0, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, 0, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, 0, I1 }, +{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, 0, I1 }, +{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, 0, I1 }, +{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, 0, I1 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, 0, I1 }, +{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, 0, I1 }, +{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, 0, I1 }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, 0, I1 }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, 0, I1 }, +{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, 0, I1 }, +{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, 0, I1 }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, 0, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +/* ssnop is at the start of the table. */ +{"standby", "", 0x42000021, 0xffffffff, 0, 0, V1 }, +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, 0, I1 }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1 }, +{"suspend", "", 0x42000022, 0xffffffff, 0, 0, V1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, 0, I5|I33|N55}, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, 0, I1 }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, 0, I1 }, +{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, 0, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, /* swc1 */ +{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I1 }, +{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, 0, I1 }, +{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, 0, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I2 }, /* as swl */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, 0, I2 }, /* as swr */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S, 0, I4|I33 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2|G1 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, 0, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, 0, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, 0, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* teqi */ +{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, 0, I2 }, +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgei */ +{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, 0, I2 }, +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgeiu */ +{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, 0, I2 }, +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tlti */ +{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, 0, I2 }, +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tltiu */ +{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, 0, I2 }, +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tnei */ +{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, 0, I2 }, +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, 0, I1 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, 0, I1 }, +{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, 0, I3 }, +{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, 0, I3 }, +{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, 0, I1 }, +{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, 0, I1 }, +{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, 0, I1 }, +{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, 0, I1 }, +{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, 0, I1 }, +{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, 0, I1 }, +{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, 0, I3 }, +{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, 0, I3 }, +{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, 0, I1 }, +{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, 0, I1 }, +{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, 0, I1 }, +{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, 0, I1 }, +{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX|SB1 }, +{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, 0, N54 }, +{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX }, +{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, 0, N54 }, +{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, 0, I3|I32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, 0, I32|N55 }, +{"waiti", "", 0x42000020, 0xffffffff, TRAP, 0, L1 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, 0, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, 0, I1 }, +{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"yield", "s", 0x7c000009, 0xfc1fffff, TRAP|RD_s, 0, MT32 }, +{"yield", "d,s", 0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s, 0, MT32 }, + +/* User Defined Instruction. */ +{"udi0", "s,t,d,+1",0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,t,+2", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,+3", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "+4", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,d,+1",0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,+2", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,+3", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "+4", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,d,+1",0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,+2", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,+3", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "+4", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,d,+1",0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,+2", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,+3", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "+4", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,d,+1",0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,+2", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,+3", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "+4", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,d,+1",0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,+2", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,+3", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "+4", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,d,+1",0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,+2", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,+3", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "+4", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,d,+1",0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,+2", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,+3", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "+4", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,d,+1",0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,+2", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,+3", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "+4", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,d,+1",0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,+2", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,+3", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "+4", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,d,+1",0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,+2", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,+3", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "+4", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,d,+1",0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,+2", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,+3", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "+4", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,d,+1",0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,+2", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,+3", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "+4", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,d,+1",0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,+2", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,+3", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "+4", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,d,+1",0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,+2", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,+3", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "+4", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,d,+1",0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,+2", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,+3", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "+4", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, + +/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format + instructions so they are here for the latters to take precedence. */ +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2f", "N,p", 0x49000000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2fl", "N,p", 0x49020000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2t", "N,p", 0x49010000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2tl", "N,p", 0x49030000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I64 }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I32 }, +{"mfhc2", "t,G", 0x48600000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,G,H", 0x48600000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, 0, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I32 }, +{"mthc2", "t,G", 0x48e00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, I33 }, + +/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X + instructions, so they are here for the latters to take precedence. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I3 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I3 }, +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 0, I32 }, +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, 0, I32 }, + +/* No hazard protection on coprocessor instructions--they shouldn't + change the state of the processor and if they do it's up to the + user to put in nops as necessary. These are at the end so that the + disassembler recognizes more specific versions first. */ +{"c0", "C", 0x42000000, 0xfe000000, 0, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, 0, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, 0, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, 0, 0, I1 }, +{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, 0, I1 }, +{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, 0, I1 }, +{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, 0, I1 }, +{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, 0, I1 }, + /* Conflicts with the 4650's "mul" instruction. Nobody's using the + 4010 any more, so move this insn out of the way. If the object + format gave us more info, we could do this right. */ +{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, 0, L1 }, +/* MIPS DSP ASE */ +{"absq_s.ph", "d,t", 0x7c000252, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"absq_s.pw", "d,t", 0x7c000456, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.qh", "d,t", 0x7c000256, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.w", "d,t", 0x7c000452, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"addq.ph", "d,s,t", 0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq.pw", "d,s,t", 0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq.qh", "d,s,t", 0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.ph", "d,s,t", 0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq_s.pw", "d,s,t", 0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.qh", "d,s,t", 0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.w", "d,s,t", 0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addsc", "d,s,t", 0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu.ob", "d,s,t", 0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu.qb", "d,s,t", 0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu_s.ob", "d,s,t", 0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu_s.qb", "d,s,t", 0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addwc", "d,s,t", 0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"bitrev", "d,t", 0x7c0006d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"bposge32", "p", 0x041c0000, 0xffff0000, CBD, 0, D32 }, +{"bposge64", "p", 0x041d0000, 0xffff0000, CBD, 0, D64 }, +{"cmp.eq.ph", "s,t", 0x7c000211, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.eq.pw", "s,t", 0x7c000415, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.eq.qh", "s,t", 0x7c000215, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmp.le.ph", "s,t", 0x7c000291, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.le.pw", "s,t", 0x7c000495, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.le.qh", "s,t", 0x7c000295, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.ph", "s,t", 0x7c000251, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.lt.pw", "s,t", 0x7c000455, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.qh", "s,t", 0x7c000255, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.ob", "s,t", 0x7c000015, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.qb", "s,t", 0x7c000011, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.le.ob", "s,t", 0x7c000095, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.le.qb", "s,t", 0x7c000091, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.lt.ob", "s,t", 0x7c000055, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.lt.qb", "s,t", 0x7c000051, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"dextpdp", "t,7,6", 0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D64 }, +{"dextpdpv", "t,7,s", 0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D64 }, +{"dextp", "t,7,6", 0x7c0000bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextpv", "t,7,s", 0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.l", "t,7,6", 0x7c00043c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.l", "t,7,6", 0x7c00053c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.l", "t,7,6", 0x7c0005bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.w", "t,7,6", 0x7c0001bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.w", "t,7,6", 0x7c00013c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_s.h", "t,7,6", 0x7c0003bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextrv.l", "t,7,s", 0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.l", "t,7,s", 0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.w", "t,7,s", 0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_s.h", "t,7,s", 0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv.w", "t,7,s", 0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.w", "t,7,6", 0x7c00003c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dinsv", "t,s", 0x7c00000d, 0xfc00ffff, WR_t|RD_s, 0, D64 }, +{"dmadd", "7,s,t", 0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmaddu", "7,s,t", 0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsub", "7,s,t", 0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsubu", "7,s,t", 0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmthlip", "s,7", 0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D64 }, +{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obl", "7,s,t", 0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obr", "7,s,t", 0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.qbl", "7,s,t", 0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpau.h.qbr", "7,s,t", 0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obl", "7,s,t", 0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obr", "7,s,t", 0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.qbl", "7,s,t", 0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsu.h.qbr", "7,s,t", 0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dshilo", "7,:", 0x7c0006bc, 0xfc07e7ff, MOD_a, 0, D64 }, +{"dshilov", "7,s", 0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s, 0, D64 }, +{"extpdp", "t,7,6", 0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D32 }, +{"extpdpv", "t,7,s", 0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D32 }, +{"extp", "t,7,6", 0x7c0000b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extpv", "t,7,s", 0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr_rs.w", "t,7,6", 0x7c0001b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_r.w", "t,7,6", 0x7c000138, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_s.h", "t,7,6", 0x7c0003b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extrv_rs.w", "t,7,s", 0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_r.w", "t,7,s", 0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_s.h", "t,7,s", 0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv.w", "t,7,s", 0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr.w", "t,7,6", 0x7c000038, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"insv", "t,s", 0x7c00000c, 0xfc00ffff, WR_t|RD_s, 0, D32 }, +{"lbux", "d,t(b)", 0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"ldx", "d,t(b)", 0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D64 }, +{"lhx", "d,t(b)", 0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"lwx", "d,t(b)", 0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"modsub", "d,s,t", 0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"mthlip", "s,7", 0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D32 }, +{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulq_rs.ph", "d,s,t", 0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"mulq_rs.qh", "d,s,t", 0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"packrl.ph", "d,s,t", 0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"packrl.pw", "d,s,t", 0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ob", "d,s,t", 0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ph", "d,s,t", 0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.pw", "d,s,t", 0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.qb", "d,s,t", 0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.qh", "d,s,t", 0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.w.phl", "d,t", 0x7c000312, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceq.w.phr", "d,t", 0x7c000352, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"raddu.l.ob", "d,s", 0x7c000514, 0xfc1f07ff, WR_d|RD_s, 0, D64 }, +{"raddu.w.qb", "d,s", 0x7c000510, 0xfc1f07ff, WR_d|RD_s, 0, D32 }, +{"rddsp", "d", 0x7fff04b8, 0xffff07ff, WR_d, 0, D32 }, +{"rddsp", "d,'", 0x7c0004b8, 0xffc007ff, WR_d, 0, D32 }, +{"repl.ob", "d,5", 0x7c000096, 0xff0007ff, WR_d, 0, D64 }, +{"repl.ph", "d,@", 0x7c000292, 0xfc0007ff, WR_d, 0, D32 }, +{"repl.pw", "d,@", 0x7c000496, 0xfc0007ff, WR_d, 0, D64 }, +{"repl.qb", "d,5", 0x7c000092, 0xff0007ff, WR_d, 0, D32 }, +{"repl.qh", "d,@", 0x7c000296, 0xfc0007ff, WR_d, 0, D64 }, +{"replv.ob", "d,t", 0x7c0000d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.ph", "d,t", 0x7c0002d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.pw", "d,t", 0x7c0004d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.qb", "d,t", 0x7c0000d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.qh", "d,t", 0x7c0002d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"shilo", "7,0", 0x7c0006b8, 0xfc0fe7ff, MOD_a, 0, D32 }, +{"shilov", "7,s", 0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s, 0, D32 }, +{"shll.ob", "d,t,3", 0x7c000017, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shll.ph", "d,t,4", 0x7c000213, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll.pw", "d,t,6", 0x7c000417, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll.qb", "d,t,3", 0x7c000013, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shll.qh", "d,t,4", 0x7c000217, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.ph", "d,t,4", 0x7c000313, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll_s.pw", "d,t,6", 0x7c000517, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.qh", "d,t,4", 0x7c000317, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.w", "d,t,6", 0x7c000513, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shllv.ob", "d,t,s", 0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.ph", "d,t,s", 0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.pw", "d,t,s", 0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.qb", "d,t,s", 0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.qh", "d,t,s", 0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.ph", "d,t,s", 0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv_s.pw", "d,t,s", 0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.qh", "d,t,s", 0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.w", "d,t,s", 0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shra.ph", "d,t,4", 0x7c000253, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra.pw", "d,t,6", 0x7c000457, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra.qh", "d,t,4", 0x7c000257, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.ph", "d,t,4", 0x7c000353, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra_r.pw", "d,t,6", 0x7c000557, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.qh", "d,t,4", 0x7c000357, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.w", "d,t,6", 0x7c000553, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shrav.ph", "d,t,s", 0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav.pw", "d,t,s", 0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav.qh", "d,t,s", 0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.ph", "d,t,s", 0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav_r.pw", "d,t,s", 0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.qh", "d,t,s", 0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.w", "d,t,s", 0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrl.ob", "d,t,3", 0x7c000057, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shrl.qb", "d,t,3", 0x7c000053, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shrlv.ob", "d,t,s", 0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrlv.qb", "d,t,s", 0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.ph", "d,s,t", 0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.pw", "d,s,t", 0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq.qh", "d,s,t", 0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.ph", "d,s,t", 0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq_s.pw", "d,s,t", 0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.qh", "d,s,t", 0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.w", "d,s,t", 0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu.ob", "d,s,t", 0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu.qb", "d,s,t", 0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu_s.ob", "d,s,t", 0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu_s.qb", "d,s,t", 0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"wrdsp", "s", 0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA, 0, D32 }, +{"wrdsp", "s,8", 0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA, 0, D32 }, +/* MIPS DSP ASE Rev2 */ +{"absq_s.qb", "d,t", 0x7c000052, 0xffe007ff, WR_d|RD_t, 0, D33 }, +{"addu.ph", "d,s,t", 0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addu_s.ph", "d,s,t", 0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh.qb", "d,s,t", 0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh_r.qb", "d,s,t", 0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"append", "t,s,h", 0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"balign", "t,s,I", 0, (int) M_BALIGN, INSN_MACRO, 0, D33 }, +{"balign", "t,s,2", 0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s, 0, D33 }, +{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpa.w.ph", "7,s,t", 0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dps.w.ph", "7,s,t", 0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mul.ph", "d,s,t", 0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mul_s.ph", "d,s,t", 0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_rs.w", "d,s,t", 0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.ph", "d,s,t", 0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.w", "d,s,t", 0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulsa.w.ph", "7,s,t", 0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"prepend", "t,s,h", 0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"shra.qb", "d,t,3", 0x7c000113, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shra_r.qb", "d,t,3", 0x7c000153, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shrav.qb", "d,t,s", 0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrav_r.qb", "d,t,s", 0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrl.ph", "d,t,4", 0x7c000653, 0xfe0007ff, WR_d|RD_t, 0, D33 }, +{"shrlv.ph", "d,t,s", 0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu.ph", "d,s,t", 0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu_s.ph", "d,s,t", 0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh.qb", "d,s,t", 0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh_r.qb", "d,s,t", 0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.ph", "d,s,t", 0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.ph", "d,s,t", 0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.w", "d,s,t", 0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.w", "d,s,t", 0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.ph", "d,s,t", 0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.ph", "d,s,t", 0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.w", "d,s,t", 0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.w", "d,s,t", 0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpax.w.ph", "7,s,t", 0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsx.w.ph", "7,s,t", 0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +/* Move bc0* after mftr and mttr to avoid opcode collision. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +}; + +#define MIPS_NUM_OPCODES \ + ((sizeof mips_builtin_opcodes) / (sizeof (mips_builtin_opcodes[0]))) +const int bfd_mips_num_builtin_opcodes = MIPS_NUM_OPCODES; + +/* const removed from the following to allow for dynamic extensions to the + * built-in instruction set. */ +struct mips_opcode *mips_opcodes = + (struct mips_opcode *) mips_builtin_opcodes; +int bfd_mips_num_opcodes = MIPS_NUM_OPCODES; +#undef MIPS_NUM_OPCODES + +/* Mips instructions are at maximum this many bytes long. */ +#define INSNLEN 4 + + +/* FIXME: These should be shared with gdb somehow. */ + +struct mips_cp0sel_name +{ + unsigned int cp0reg; + unsigned int sel; + const char * const name; +}; + +/* The mips16 registers. */ +static const unsigned int mips16_to_32_reg_map[] = +{ + 16, 17, 2, 3, 4, 5, 6, 7 +}; + +#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] + + +static const char * const mips_gpr_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_gpr_names_oldabi[32] = +{ + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_gpr_names_newabi[32] = +{ + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_fpr_names_numeric[32] = +{ + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +static const char * const mips_fpr_names_32[32] = +{ + "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f", + "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f", + "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f", + "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f" +}; + +static const char * const mips_fpr_names_n32[32] = +{ + "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9", + "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13" +}; + +static const char * const mips_fpr_names_64[32] = +{ + "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" +}; + +static const char * const mips_cp0_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_cp0_names_mips3264[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = +{ + { 4, 1, "c0_contextconfig" }, + { 0, 1, "c0_mvpcontrol" }, + { 0, 2, "c0_mvpconf0" }, + { 0, 3, "c0_mvpconf1" }, + { 1, 1, "c0_vpecontrol" }, + { 1, 2, "c0_vpeconf0" }, + { 1, 3, "c0_vpeconf1" }, + { 1, 4, "c0_yqmask" }, + { 1, 5, "c0_vpeschedule" }, + { 1, 6, "c0_vpeschefback" }, + { 2, 1, "c0_tcstatus" }, + { 2, 2, "c0_tcbind" }, + { 2, 3, "c0_tcrestart" }, + { 2, 4, "c0_tchalt" }, + { 2, 5, "c0_tccontext" }, + { 2, 6, "c0_tcschedule" }, + { 2, 7, "c0_tcschefback" }, + { 5, 1, "c0_pagegrain" }, + { 6, 1, "c0_srsconf0" }, + { 6, 2, "c0_srsconf1" }, + { 6, 3, "c0_srsconf2" }, + { 6, 4, "c0_srsconf3" }, + { 6, 5, "c0_srsconf4" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, +}; + +static const char * const mips_cp0_names_mips3264r2[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = +{ + { 4, 1, "c0_contextconfig" }, + { 5, 1, "c0_pagegrain" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, +}; + +/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */ +static const char * const mips_cp0_names_sb1[32] = +{ + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i", + "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = +{ + { 16, 1, "c0_config1" }, + { 18, 1, "c0_watchlo,1" }, + { 19, 1, "c0_watchhi,1" }, + { 22, 0, "c0_perftrace" }, + { 23, 3, "c0_edebug" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 26, 1, "c0_buserr_pa" }, + { 27, 1, "c0_cacheerr_d" }, + { 27, 3, "c0_cacheerr_d_pa" }, + { 28, 1, "c0_datalo_i" }, + { 28, 2, "c0_taglo_d" }, + { 28, 3, "c0_datalo_d" }, + { 29, 1, "c0_datahi_i" }, + { 29, 2, "c0_taghi_d" }, + { 29, 3, "c0_datahi_d" }, +}; + +static const char * const mips_hwr_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_hwr_names_mips3264r2[32] = +{ + "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", + "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +struct mips_abi_choice +{ + const char *name; + const char * const *gpr_names; + const char * const *fpr_names; +}; + +struct mips_abi_choice mips_abi_choices[] = +{ + { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, + { "32", mips_gpr_names_oldabi, mips_fpr_names_32 }, + { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 }, + { "64", mips_gpr_names_newabi, mips_fpr_names_64 }, +}; + +struct mips_arch_choice +{ + const char *name; + int bfd_mach_valid; + unsigned long bfd_mach; + int processor; + int isa; + const char * const *cp0_names; + const struct mips_cp0sel_name *cp0sel_names; + unsigned int cp0sel_names_len; + const char * const *hwr_names; +}; + +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4111 4111 +#define bfd_mach_mips4120 4120 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips5400 5400 +#define bfd_mach_mips5500 5500 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips7000 7000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips9000 9000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips12000 12000 +#define bfd_mach_mips16 16 +#define bfd_mach_mips5 5 +#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ +#define bfd_mach_mipsisa32 32 +#define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa64 64 +#define bfd_mach_mipsisa64r2 65 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +const struct mips_arch_choice mips_arch_choices[] = +{ + { "numeric", 0, 0, 0, 0, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs. + Note that MIPS-3D and MDMX are not applicable to MIPS32. (See + _MIPS32 Architecture For Programmers Volume I: Introduction to the + MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95), + page 1. */ + { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32, + ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, + (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 + | INSN_MIPS3D | INSN_MT), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */ + { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64, + ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2, + (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2 + | INSN_DSP64 | INSN_MT | INSN_MDMX), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, + ISA_MIPS64 | INSN_MIPS3D | INSN_SB1, + mips_cp0_names_sb1, + mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1), + mips_hwr_names_numeric }, + + /* This entry, mips16, is here only for ISA/processor selection; do + not print its name. */ + { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, +}; + +/* ISA and processor type to disassemble for, and register names to use. + set_default_mips_dis_options and parse_mips_dis_options fill in these + values. */ +static int mips_processor; +static int mips_isa; +static const char * const *mips_gpr_names; +static const char * const *mips_fpr_names; +static const char * const *mips_cp0_names; +static const struct mips_cp0sel_name *mips_cp0sel_names; +static int mips_cp0sel_names_len; +static const char * const *mips_hwr_names; + +/* Other options */ +static int no_aliases; /* If set disassemble as most general inst. */ + +static const struct mips_abi_choice * +choose_abi_by_name (const char *name, unsigned int namelen) +{ + const struct mips_abi_choice *c; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) + if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 + && strlen (mips_abi_choices[i].name) == namelen) + c = &mips_abi_choices[i]; + + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_name (const char *name, unsigned int namelen) +{ + const struct mips_arch_choice *c = NULL; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 + && strlen (mips_arch_choices[i].name) == namelen) + c = &mips_arch_choices[i]; + + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_number (unsigned long mach) +{ + static unsigned long hint_bfd_mach; + static const struct mips_arch_choice *hint_arch_choice; + const struct mips_arch_choice *c; + unsigned int i; + + /* We optimize this because even if the user specifies no + flags, this will be done for every instruction! */ + if (hint_bfd_mach == mach + && hint_arch_choice != NULL + && hint_arch_choice->bfd_mach == hint_bfd_mach) + return hint_arch_choice; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + { + if (mips_arch_choices[i].bfd_mach_valid + && mips_arch_choices[i].bfd_mach == mach) + { + c = &mips_arch_choices[i]; + hint_bfd_mach = mach; + hint_arch_choice = c; + } + } + return c; +} + +static void +set_default_mips_dis_options (struct disassemble_info *info) +{ + const struct mips_arch_choice *chosen_arch; + + /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names, + and numeric FPR, CP0 register, and HWR names. */ + mips_isa = ISA_MIPS3; + mips_processor = CPU_R3000; + mips_gpr_names = mips_gpr_names_oldabi; + mips_fpr_names = mips_fpr_names_numeric; + mips_cp0_names = mips_cp0_names_numeric; + mips_cp0sel_names = NULL; + mips_cp0sel_names_len = 0; + mips_hwr_names = mips_hwr_names_numeric; + no_aliases = 0; + + /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ +#if 0 + if (info->flavour == bfd_target_elf_flavour && info->section != NULL) + { + Elf_Internal_Ehdr *header; + + header = elf_elfheader (info->section->owner); + if (is_newabi (header)) + mips_gpr_names = mips_gpr_names_newabi; + } +#endif + + /* Set ISA, architecture, and cp0 register names as best we can. */ +#if !defined(SYMTAB_AVAILABLE) && 0 + /* This is running out on a target machine, not in a host tool. + FIXME: Where does mips_target_info come from? */ + target_processor = mips_target_info.processor; + mips_isa = mips_target_info.isa; +#else + chosen_arch = choose_arch_by_number (info->mach); + if (chosen_arch != NULL) + { + mips_processor = chosen_arch->processor; + mips_isa = chosen_arch->isa; + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } +#endif +} + +static void +parse_mips_dis_option (const char *option, unsigned int len) +{ + unsigned int i, optionlen, vallen; + const char *val; + const struct mips_abi_choice *chosen_abi; + const struct mips_arch_choice *chosen_arch; + + /* Look for the = that delimits the end of the option name. */ + for (i = 0; i < len; i++) + { + if (option[i] == '=') + break; + } + if (i == 0) /* Invalid option: no name before '='. */ + return; + if (i == len) /* Invalid option: no '='. */ + return; + if (i == (len - 1)) /* Invalid option: no value after '='. */ + return; + + optionlen = i; + val = option + (optionlen + 1); + vallen = len - (optionlen + 1); + + if (strncmp("gpr-names", option, optionlen) == 0 + && strlen("gpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_gpr_names = chosen_abi->gpr_names; + return; + } + + if (strncmp("fpr-names", option, optionlen) == 0 + && strlen("fpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_fpr_names = chosen_abi->fpr_names; + return; + } + + if (strncmp("cp0-names", option, optionlen) == 0 + && strlen("cp0-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + } + return; + } + + if (strncmp("hwr-names", option, optionlen) == 0 + && strlen("hwr-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + mips_hwr_names = chosen_arch->hwr_names; + return; + } + + if (strncmp("reg-names", option, optionlen) == 0 + && strlen("reg-names") == optionlen) + { + /* We check both ABI and ARCH here unconditionally, so + that "numeric" will do the desirable thing: select + numeric register names for all registers. Other than + that, a given name probably won't match both. */ + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + { + mips_gpr_names = chosen_abi->gpr_names; + mips_fpr_names = chosen_abi->fpr_names; + } + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } + return; + } + + /* Invalid option. */ +} + +static void +parse_mips_dis_options (const char *options) +{ + const char *option_end; + + if (options == NULL) + return; + + while (*options != '\0') + { + /* Skip empty options. */ + if (*options == ',') + { + options++; + continue; + } + + /* We know that *options is neither NUL or a comma. */ + option_end = options + 1; + while (*option_end != ',' && *option_end != '\0') + option_end++; + + parse_mips_dis_option (options, option_end - options); + + /* Go on to the next one. If option_end points to a comma, it + will be skipped above. */ + options = option_end; + } +} + +static const struct mips_cp0sel_name * +lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names, + unsigned int len, + unsigned int cp0reg, + unsigned int sel) +{ + unsigned int i; + + for (i = 0; i < len; i++) + if (names[i].cp0reg == cp0reg && names[i].sel == sel) + return &names[i]; + return NULL; +} + +/* Print insn arguments for 32/64-bit code. */ + +static void +print_insn_args (const char *d, + register unsigned long int l, + bfd_vma pc, + struct disassemble_info *info, + const struct mips_opcode *opp) +{ + int op, delta; + unsigned int lsb, msb, msbd; + + lsb = 0; + + for (; *d != '\0'; d++) + { + switch (*d) + { + case ',': + case '(': + case ')': + case '[': + case ']': + (*info->fprintf_func) (info->stream, "%c", *d); + break; + + case '+': + /* Extension character; switch for second char. */ + d++; + switch (*d) + { + case '\0': + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, incomplete extension sequence (+)")); + return; + + case 'A': + lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'B': + msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case '1': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI1) & OP_MASK_UDI1); + break; + + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI2) & OP_MASK_UDI2); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI3) & OP_MASK_UDI3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI4) & OP_MASK_UDI4); + break; + + case 'C': + case 'H': + msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + case 'D': + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mtcN (et al.), to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + + case 'E': + lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'F': + msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case 'G': + msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + case 't': /* Coprocessor 0 reg name */ + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RT) & + OP_MASK_RT]); + break; + + case 'T': /* Coprocessor 0 reg name */ + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mftc0, to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined extension sequence (+%c)"), + *d); + return; + } + break; + + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_BP) & OP_MASK_BP); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA3) & OP_MASK_SA3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA4) & OP_MASK_SA4); + break; + + case '5': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_IMM8) & OP_MASK_IMM8); + break; + + case '6': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RS) & OP_MASK_RS); + break; + + case '7': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); + break; + + case '8': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); + break; + + case '9': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); + break; + + case '0': /* dsp 6-bit signed immediate in bit 20 */ + delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); + if (delta & 0x20) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case ':': /* dsp 7-bit signed immediate in bit 19 */ + delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); + if (delta & 0x40) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT_7; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '\'': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); + break; + + case '@': /* dsp 10-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) /* test sign bit */ + delta |= ~OP_MASK_IMM10; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '!': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_U) & OP_MASK_MT_U); + break; + + case '$': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_H) & OP_MASK_MT_H); + break; + + case '*': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); + break; + + case '&': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); + break; + + case 'g': + /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 's': + case 'b': + case 'r': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); + break; + + case 't': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'i': + case 'u': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); + break; + + case 'j': /* Same as i, but sign-extended. */ + case 'o': + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + (*info->fprintf_func) (info->stream, "%d", + delta); + break; + + case 'h': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_PREFX) + & OP_MASK_PREFX)); + break; + + case 'k': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_CACHE) + & OP_MASK_CACHE)); + break; + + case 'a': + info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + /* For gdb disassembler, force odd address on jalx. */ + if (info->flavour == bfd_target_unknown_flavour + && strcmp (opp->name, "jalx") == 0) + info->target |= 1; + (*info->print_address_func) (info->target, info); + break; + + case 'p': + /* Sign extend the displacement. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + + case 'd': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'U': + { + /* First check for both rd and rt being equal. */ + unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else + { + /* If one is zero use the other. */ + if (reg == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else /* Bogus, result depends on processor. */ + (*info->fprintf_func) (info->stream, "%s or %s", + mips_gpr_names[reg], + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case '<': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); + break; + + case 'c': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE) & OP_MASK_CODE); + break; + + case 'q': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE2) & OP_MASK_CODE2); + break; + + case 'C': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_COPZ) & OP_MASK_COPZ); + break; + + case 'B': + (*info->fprintf_func) (info->stream, "0x%lx", + + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); + break; + + case 'S': + case 'V': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'T': + case 'W': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); + break; + + case 'E': + /* Coprocessor register for lwcN instructions, et al. + + Note that there is no load/store cp0 instructions, and + that FPU (cp1) instructions disassemble this field using + 'T' format. Therefore, until we gain understanding of + cp2 register names, we can simply print the register + numbers. */ + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RT) & OP_MASK_RT); + break; + + case 'G': + /* Coprocessor register for mtcN instructions, et al. Note + that FPU (cp1) instructions disassemble this field using + 'S' format. Therefore, we only need to worry about cp0, + cp2, and cp3. */ + op = (l >> OP_SH_OP) & OP_MASK_OP; + if (op == OP_OP_COP0) + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); + else + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 'K': + (*info->fprintf_func) (info->stream, "%s", + mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'N': + (*info->fprintf_func) (info->stream, + ((opp->pinfo & (FP_D | FP_S)) != 0 + ? "$fcc%ld" : "$cc%ld"), + (l >> OP_SH_BCC) & OP_MASK_BCC); + break; + + case 'M': + (*info->fprintf_func) (info->stream, "$fcc%ld", + (l >> OP_SH_CCC) & OP_MASK_CCC); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); + break; + + case 'e': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); + break; + + case '%': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_SEL) & OP_MASK_SEL); + break; + + case 'O': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_ALN) & OP_MASK_ALN); + break; + + case 'Q': + { + unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + + if ((vsel & 0x10) == 0) + { + int fmt; + + vsel &= 0x0f; + for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) + if ((vsel & 1) == 0) + break; + (*info->fprintf_func) (info->stream, "$v%ld[%d]", + (l >> OP_SH_FT) & OP_MASK_FT, + vsel >> 1); + } + else if ((vsel & 0x08) == 0) + { + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + } + else + { + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_FT) & OP_MASK_FT); + } + } + break; + + case 'X': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FD) & OP_MASK_FD); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FS) & OP_MASK_FS); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined modifier(%c)"), + *d); + return; + } + } +} + +/* Check if the object uses NewABI conventions. */ +#if 0 +static int +is_newabi (header) + Elf_Internal_Ehdr *header; +{ + /* There are no old-style ABIs which use 64-bit ELF. */ + if (header->e_ident[EI_CLASS] == ELFCLASS64) + return 1; + + /* If a 32-bit ELF file, n32 is a new-style ABI. */ + if ((header->e_flags & EF_MIPS_ABI2) != 0) + return 1; + + return 0; +} +#endif + +/* Print the mips instruction at address MEMADDR in debugged memory, + on using INFO. Returns length of the instruction, in bytes, which is + always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if + this is little-endian code. */ + +static int +print_insn_mips (bfd_vma memaddr, + unsigned long int word, + struct disassemble_info *info) +{ + const struct mips_opcode *op; + static bfd_boolean init = 0; + static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; + + /* Build a hash table to shorten the search time. */ + if (! init) + { + unsigned int i; + + for (i = 0; i <= OP_MASK_OP; i++) + { + for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo == INSN_MACRO + || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) + continue; + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) + { + mips_hash[i] = op; + break; + } + } + } + + init = 1; + } + + info->bytes_per_chunk = INSNLEN; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; + if (op != NULL) + { + for (; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (word & op->mask) == op->match) + { + const char *d; + + /* We always allow to disassemble the jalx instruction. */ + if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor) + && strcmp (op->name, "jalx")) + continue; + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_jsr; + else + info->insn_type = dis_branch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_condjsr; + else + info->insn_type = dis_condbranch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_STORE_MEMORY + | INSN_LOAD_MEMORY_DELAY)) != 0) + info->insn_type = dis_dref; + + (*info->fprintf_func) (info->stream, "%s", op->name); + + d = op->args; + if (d != NULL && *d != '\0') + { + (*info->fprintf_func) (info->stream, "\t"); + print_insn_args (d, word, memaddr, info, op); + } + + return INSNLEN; + } + } + } + + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream, "0x%lx", word); + return INSNLEN; +} + +/* In an environment where we do not know the symbol type of the + instruction we are forced to assume that the low order bit of the + instructions' address may mark it as a mips16 instruction. If we + are single stepping, or the pc is within the disassembled function, + this works. Otherwise, we need a clue. Sometimes. */ + +static int +_print_insn_mips (bfd_vma memaddr, + struct disassemble_info *info, + enum bfd_endian endianness) +{ + bfd_byte buffer[INSNLEN]; + int status; + + set_default_mips_dis_options (info); + parse_mips_dis_options (info->disassembler_options); + +#if 0 +#if 1 + /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */ + /* Only a few tools will work this way. */ + if (memaddr & 0x01) + return print_insn_mips16 (memaddr, info); +#endif + +#if SYMTAB_AVAILABLE + if (info->mach == bfd_mach_mips16 + || (info->flavour == bfd_target_elf_flavour + && info->symbols != NULL + && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other + == STO_MIPS16))) + return print_insn_mips16 (memaddr, info); +#endif +#endif + + status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info); + if (status == 0) + { + unsigned long insn; + + if (endianness == BFD_ENDIAN_BIG) + insn = (unsigned long) bfd_getb32 (buffer); + else + insn = (unsigned long) bfd_getl32 (buffer); + + return print_insn_mips (memaddr, insn, info); + } + else + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } +} + +int +print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info) +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG); +} + +int +print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info) +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); +} + +/* Disassemble mips16 instructions. */ +#if 0 +static int +print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) +{ + int status; + bfd_byte buffer[2]; + int length; + int insn; + bfd_boolean use_extend; + int extend = 0; + const struct mips_opcode *op, *opend; + + info->bytes_per_chunk = 2; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + length = 2; + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Handle the extend opcode specially. */ + use_extend = FALSE; + if ((insn & 0xf800) == 0xf000) + { + use_extend = TRUE; + extend = insn & 0x7ff; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Check for an extend opcode followed by an extend opcode. */ + if ((insn & 0xf800) == 0xf000) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length; + } + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + + opend = mips16_opcodes + bfd_mips16_num_opcodes; + for (op = mips16_opcodes; op < opend; op++) + { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match) + { + const char *s; + + if (strchr (op->args, 'a') != NULL) + { + if (use_extend) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length - 2; + } + + use_extend = FALSE; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, + info); + if (status == 0) + { + use_extend = TRUE; + if (info->endian == BFD_ENDIAN_BIG) + extend = bfd_getb16 (buffer); + else + extend = bfd_getl16 (buffer); + length += 2; + } + } + + (*info->fprintf_func) (info->stream, "%s", op->name); + if (op->args[0] != '\0') + (*info->fprintf_func) (info->stream, "\t"); + + for (s = op->args; *s != '\0'; s++) + { + if (*s == ',' + && s[1] == 'w' + && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) + == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + if (*s == ',' + && s[1] == 'v' + && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) + == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr, + info); + } + + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + info->branch_delay_insns = 1; + if (info->insn_type != dis_jsr) + info->insn_type = dis_branch; + } + + return length; + } + } + + if (use_extend) + (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000); + (*info->fprintf_func) (info->stream, "0x%x", insn); + info->insn_type = dis_noninsn; + + return length; +} + +/* Disassemble an operand for a mips16 instruction. */ + +static void +print_mips16_insn_arg (char type, + const struct mips_opcode *op, + int l, + bfd_boolean use_extend, + int extend, + bfd_vma memaddr, + struct disassemble_info *info) +{ + switch (type) + { + case ',': + case '(': + case ')': + (*info->fprintf_func) (info->stream, "%c", type); + break; + + case 'y': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY))); + break; + + case 'x': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX))); + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ))); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z))); + break; + + case '0': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "$pc"); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]); + break; + + case 'X': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[((l >> MIPS16OP_SH_REGR32) + & MIPS16OP_MASK_REGR32)]); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); + break; + + case '<': + case '>': + case '[': + case ']': + case '4': + case '5': + case 'H': + case 'W': + case 'D': + case 'j': + case '6': + case '8': + case 'V': + case 'C': + case 'U': + case 'k': + case 'K': + case 'p': + case 'q': + case 'A': + case 'B': + case 'E': + { + int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; + + shift = 0; + signedp = 0; + extbits = 16; + pcrel = 0; + extu = 0; + branch = 0; + switch (type) + { + case '<': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 5; + extu = 1; + break; + case '>': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 5; + extu = 1; + break; + case '[': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 6; + extu = 1; + break; + case ']': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 6; + extu = 1; + break; + case '4': + nbits = 4; + immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; + signedp = 1; + extbits = 15; + break; + case '5': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 1; + break; + case 'H': + nbits = 5; + shift = 1; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 2; + break; + case 'W': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 + && (op->pinfo & MIPS16_INSN_READ_SP) == 0) + { + info->insn_type = dis_dref; + info->data_size = 4; + } + break; + case 'D': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'j': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + signedp = 1; + break; + case '6': + nbits = 6; + immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + break; + case '8': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + break; + case 'V': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + /* FIXME: This might be lw, or it might be addiu to $sp or + $pc. We assume it's load. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'C': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'U': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + extu = 1; + break; + case 'k': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'K': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'p': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_condbranch; + break; + case 'q': + nbits = 11; + immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_branch; + break; + case 'A': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + pcrel = 1; + /* FIXME: This can be lw or la. We assume it is lw. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'B': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'E': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + break; + default: + abort (); + } + + if (! use_extend) + { + if (signedp && immed >= (1 << (nbits - 1))) + immed -= 1 << nbits; + immed <<= shift; + if ((type == '<' || type == '>' || type == '[' || type == ']') + && immed == 0) + immed = 8; + } + else + { + if (extbits == 16) + immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); + else if (extbits == 15) + immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); + else + immed = ((extend >> 6) & 0x1f) | (extend & 0x20); + immed &= (1 << extbits) - 1; + if (! extu && immed >= (1 << (extbits - 1))) + immed -= 1 << extbits; + } + + if (! pcrel) + (*info->fprintf_func) (info->stream, "%d", immed); + else + { + bfd_vma baseaddr; + + if (branch) + { + immed *= 2; + baseaddr = memaddr + 2; + } + else if (use_extend) + baseaddr = memaddr - 2; + else + { + int status; + bfd_byte buffer[2]; + + baseaddr = memaddr; + + /* If this instruction is in the delay slot of a jr + instruction, the base address is the address of the + jr instruction. If it is in the delay slot of jalr + instruction, the base address is the address of the + jalr instruction. This test is unreliable: we have + no way of knowing whether the previous word is + instruction or data. */ + status = (*info->read_memory_func) (memaddr - 4, buffer, 2, + info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else + { + status = (*info->read_memory_func) (memaddr - 2, buffer, + 2, info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf81f) == 0xe800)) + baseaddr = memaddr - 2; + } + } + info->target = (baseaddr & ~((1 << shift) - 1)) + immed; + if (pcrel && branch + && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + info->target |= 1; + (*info->print_address_func) (info->target, info); + } + } + break; + + case 'a': + { + int jalx = l & 0x400; + + if (! use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + if (!jalx && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + l |= 1; + } + info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l; + (*info->print_address_func) (info->target, info); + info->insn_type = dis_jsr; + info->branch_delay_insns = 1; + break; + + case 'l': + case 'L': + { + int need_comma, amask, smask; + + need_comma = 0; + + l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + + amask = (l >> 3) & 7; + + if (amask > 0 && amask < 5) + { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (amask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[amask + 3]); + need_comma = 1; + } + + smask = (l >> 1) & 3; + if (smask == 3) + { + (*info->fprintf_func) (info->stream, "%s??", + need_comma ? "," : ""); + need_comma = 1; + } + else if (smask > 0) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[16]); + if (smask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[smask + 15]); + need_comma = 1; + } + + if (l & 1) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[31]); + need_comma = 1; + } + + if (amask == 5 || amask == 6) + { + (*info->fprintf_func) (info->stream, "%s$f0", + need_comma ? "," : ""); + if (amask == 6) + (*info->fprintf_func) (info->stream, "-$f1"); + } + } + break; + + case 'm': + case 'M': + /* MIPS16e save/restore. */ + { + int need_comma = 0; + int amask, args, statics; + int nsreg, smask; + int framesz; + int i, j; + + l = l & 0x7f; + if (use_extend) + l |= extend << 16; + + amask = (l >> 16) & 0xf; + if (amask == MIPS16_ALL_ARGS) + { + args = 4; + statics = 0; + } + else if (amask == MIPS16_ALL_STATICS) + { + args = 0; + statics = 4; + } + else + { + args = amask >> 2; + statics = amask & 3; + } + + if (args > 0) { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (args > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[4 + args - 1]); + need_comma = 1; + } + + framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; + if (framesz == 0 && !use_extend) + framesz = 128; + + (*info->fprintf_func) (info->stream, "%s%d", + need_comma ? "," : "", + framesz); + + if (l & 0x40) /* $ra */ + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]); + + nsreg = (l >> 24) & 0x7; + smask = 0; + if (l & 0x20) /* $s0 */ + smask |= 1 << 0; + if (l & 0x10) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + /* Find first set static reg bit. */ + for (i = 0; i < 9; i++) + { + if (smask & (1 << i)) + { + (*info->fprintf_func) (info->stream, ",%s", + mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + } + + /* Statics $ax - $a3. */ + if (statics == 1) + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]); + else if (statics > 0) + (*info->fprintf_func) (info->stream, ",%s-%s", + mips_gpr_names[7 - statics + 1], + mips_gpr_names[7]); + } + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) + (info->stream, + _("# internal disassembler error, unrecognised modifier (%c)"), + type); + abort (); + } +} + +void +print_mips_disassembler_options (FILE *stream) +{ + unsigned int i; + + fprintf (stream, _("\n\ +The following MIPS specific disassembler options are supported for use\n\ +with the -M switch (multiple options should be separated by commas):\n")); + + fprintf (stream, _("\n\ + gpr-names=ABI Print GPR names according to specified ABI.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + fpr-names=ABI Print FPR names according to specified ABI.\n\ + Default: numeric.\n")); + + fprintf (stream, _("\n\ + cp0-names=ARCH Print CP0 register names according to\n\ + specified architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + hwr-names=ARCH Print HWR names according to specified \n\ + architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + reg-names=ABI Print GPR and FPR names according to\n\ + specified ABI.\n")); + + fprintf (stream, _("\n\ + reg-names=ARCH Print CP0 register and HWR names according to\n\ + specified architecture.\n")); + + fprintf (stream, _("\n\ + For the options above, the following values are supported for \"ABI\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) + fprintf (stream, " %s", mips_abi_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n\ + For the options above, The following values are supported for \"ARCH\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) + if (*mips_arch_choices[i].name != '\0') + fprintf (stream, " %s", mips_arch_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n")); +} +#endif diff --git a/qemu/qemu-git/mips.ld b/qemu/qemu-git/mips.ld new file mode 100644 index 0000000..4294761 --- /dev/null +++ b/qemu/qemu-git/mips.ld @@ -0,0 +1,224 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", + "elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(__start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x47ff041f + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/module.h b/qemu/qemu-git/module.h new file mode 100644 index 0000000..9263f1c --- /dev/null +++ b/qemu/qemu-git/module.h @@ -0,0 +1,38 @@ +/* + * QEMU Module Infrastructure + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MODULE_H +#define QEMU_MODULE_H + +/* This should not be used directly. Use block_init etc. instead. */ +#define module_init(function, type) \ +static void __attribute__((constructor)) do_qemu_init_ ## function(void) { \ + register_module_init(function, type); \ +} + +typedef enum { + MODULE_INIT_BLOCK, + MODULE_INIT_DEVICE, + MODULE_INIT_MACHINE, + MODULE_INIT_MAX +} module_init_type; + +#define block_init(function) module_init(function, MODULE_INIT_BLOCK) +#define device_init(function) module_init(function, MODULE_INIT_DEVICE) +#define machine_init(function) module_init(function, MODULE_INIT_MACHINE) + +void register_module_init(void (*fn)(void), module_init_type type); + +void module_call_init(module_init_type type); + +#endif diff --git a/qemu/qemu-git/osdep.h b/qemu/qemu-git/osdep.h new file mode 100644 index 0000000..75b5816 --- /dev/null +++ b/qemu/qemu-git/osdep.h @@ -0,0 +1,108 @@ +#ifndef QEMU_OSDEP_H +#define QEMU_OSDEP_H + +#include +#include +#ifdef __OpenBSD__ +#include +#include +#endif + +#ifndef _WIN32 +#include +#endif + +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef likely +#if __GNUC__ < 3 +#define __builtin_expect(x, n) (x) +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifdef CONFIG_NEED_OFFSETOF +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) +#endif +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *__mptr = (ptr); \ + (type *) ((char *) __mptr - offsetof(type, member));}) +#endif + +/* Convert from a base type to a parent type, with compile time checking. */ +#ifdef __GNUC__ +#define DO_UPCAST(type, field, dev) ( __extension__ ( { \ + char __attribute__((unused)) offset_must_be_zero[ \ + -offsetof(type, field)]; \ + container_of(dev, type, field);})) +#else +#define DO_UPCAST(type, field, dev) container_of(dev, type, field) +#endif + +#define typeof_field(type, field) typeof(((type *)0)->field) +#define type_check(t1,t2) ((t1*)0 - (t2*)0) + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef always_inline +#if !((__GNUC__ < 3) || defined(__APPLE__)) +#ifdef __OPTIMIZE__ +#define inline __attribute__ (( always_inline )) __inline__ +#endif +#endif +#else +#define inline always_inline +#endif + +#ifdef __i386__ +#define REGPARM __attribute((regparm(3))) +#else +#define REGPARM +#endif + +#define qemu_printf printf + +#if defined (__GNUC__) && defined (__GNUC_MINOR__) +# define QEMU_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define QEMU_GNUC_PREREQ(maj, min) 0 +#endif + +void *qemu_memalign(size_t alignment, size_t size); +void *qemu_vmalloc(size_t size); +void qemu_vfree(void *ptr); + +int qemu_create_pidfile(const char *filename); + +#ifdef _WIN32 +int ffs(int i); + +typedef struct { + long tv_sec; + long tv_usec; +} qemu_timeval; +int qemu_gettimeofday(qemu_timeval *tp); +#else +typedef struct timeval qemu_timeval; +#define qemu_gettimeofday(tp) gettimeofday(tp, NULL); +#endif /* !_WIN32 */ + +#endif diff --git a/qemu/qemu-git/ppc-dis.c b/qemu/qemu-git/ppc-dis.c new file mode 100644 index 0000000..ffdbec1 --- /dev/null +++ b/qemu/qemu-git/ppc-dis.c @@ -0,0 +1,5412 @@ +/* ppc-dis.c -- Disassemble PowerPC instructions + Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ +#include "dis-asm.h" +#define BFD_DEFAULT_TARGET_SIZE 64 + +/* ppc.h -- Header file for PowerPC opcode table + Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file; see the file COPYING. If not, +see . */ + +/* The opcode table is an array of struct powerpc_opcode. */ + +struct powerpc_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned long opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned long mask; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The defined values + are listed below. */ + unsigned long flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[8]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct powerpc_opcode powerpc_opcodes[]; +extern const int powerpc_num_opcodes; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* Opcode is defined for the PowerPC architecture. */ +#define PPC_OPCODE_PPC 1 + +/* Opcode is defined for the POWER (RS/6000) architecture. */ +#define PPC_OPCODE_POWER 2 + +/* Opcode is defined for the POWER2 (Rios 2) architecture. */ +#define PPC_OPCODE_POWER2 4 + +/* Opcode is only defined on 32 bit architectures. */ +#define PPC_OPCODE_32 8 + +/* Opcode is only defined on 64 bit architectures. */ +#define PPC_OPCODE_64 0x10 + +/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 + is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, + but it also supports many additional POWER instructions. */ +#define PPC_OPCODE_601 0x20 + +/* Opcode is supported in both the Power and PowerPC architectures + (ie, compiler's -mcpu=common or assembler's -mcom). */ +#define PPC_OPCODE_COMMON 0x40 + +/* Opcode is supported for any Power or PowerPC platform (this is + for the assembler's -many option, and it eliminates duplicates). */ +#define PPC_OPCODE_ANY 0x80 + +/* Opcode is supported as part of the 64-bit bridge. */ +#define PPC_OPCODE_64_BRIDGE 0x100 + +/* Opcode is supported by Altivec Vector Unit */ +#define PPC_OPCODE_ALTIVEC 0x200 + +/* Opcode is supported by PowerPC 403 processor. */ +#define PPC_OPCODE_403 0x400 + +/* Opcode is supported by PowerPC BookE processor. */ +#define PPC_OPCODE_BOOKE 0x800 + +/* Opcode is only supported by 64-bit PowerPC BookE processor. */ +#define PPC_OPCODE_BOOKE64 0x1000 + +/* Opcode is supported by PowerPC 440 processor. */ +#define PPC_OPCODE_440 0x2000 + +/* Opcode is only supported by Power4 architecture. */ +#define PPC_OPCODE_POWER4 0x4000 + +/* Opcode isn't supported by Power4 architecture. */ +#define PPC_OPCODE_NOPOWER4 0x8000 + +/* Opcode is only supported by POWERPC Classic architecture. */ +#define PPC_OPCODE_CLASSIC 0x10000 + +/* Opcode is only supported by e500x2 Core. */ +#define PPC_OPCODE_SPE 0x20000 + +/* Opcode is supported by e500x2 Integer select APU. */ +#define PPC_OPCODE_ISEL 0x40000 + +/* Opcode is an e500 SPE floating point instruction. */ +#define PPC_OPCODE_EFS 0x80000 + +/* Opcode is supported by branch locking APU. */ +#define PPC_OPCODE_BRLOCK 0x100000 + +/* Opcode is supported by performance monitor APU. */ +#define PPC_OPCODE_PMR 0x200000 + +/* Opcode is supported by cache locking APU. */ +#define PPC_OPCODE_CACHELCK 0x400000 + +/* Opcode is supported by machine check APU. */ +#define PPC_OPCODE_RFMCI 0x800000 + +/* Opcode is only supported by Power5 architecture. */ +#define PPC_OPCODE_POWER5 0x1000000 + +/* Opcode is supported by PowerPC e300 family. */ +#define PPC_OPCODE_E300 0x2000000 + +/* Opcode is only supported by Power6 architecture. */ +#define PPC_OPCODE_POWER6 0x4000000 + +/* Opcode is only supported by PowerPC Cell family. */ +#define PPC_OPCODE_CELL 0x8000000 + +/* A macro to extract the major opcode from an instruction. */ +#define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* The operands table is an array of struct powerpc_operand. */ + +struct powerpc_operand +{ + /* A bitmask of bits in the operand. */ + unsigned int bitm; + + /* How far the operand is left shifted in the instruction. + -1 to indicate that BITM and SHIFT cannot be used to determine + where the operand goes in the insn. */ + int shift; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & o->bitm) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the operand value). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned long (*insert) + (unsigned long instruction, long op, int dialect, const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = (i >> o->shift) & o->bitm; + if ((o->flags & PPC_OPERAND_SIGNED) != 0) + sign_extend (op); + (i is the instruction, o is a pointer to this structure, and op + is the result). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + long (*extract) (unsigned long instruction, int dialect, int *invalid); + + /* One bit syntax flags. */ + unsigned long flags; +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct powerpc_operand powerpc_operands[]; +extern const unsigned int num_powerpc_operands; + +/* Values defined for the flags field of a struct powerpc_operand. */ + +/* This operand takes signed values. */ +#define PPC_OPERAND_SIGNED (0x1) + +/* This operand takes signed values, but also accepts a full positive + range of values when running in 32 bit mode. That is, if bits is + 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, + this flag is ignored. */ +#define PPC_OPERAND_SIGNOPT (0x2) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics such as mr, for which two + operands fields are identical. The assembler should call the + insert function with any op value. The disassembler should call + the extract function, ignore the return value, and check the value + placed in the valid argument. */ +#define PPC_OPERAND_FAKE (0x4) + +/* The next operand should be wrapped in parentheses rather than + separated from this one by a comma. This is used for the load and + store instructions which want their operands to look like + reg,displacement(reg) + */ +#define PPC_OPERAND_PARENS (0x8) + +/* This operand may use the symbolic names for the CR fields, which + are + lt 0 gt 1 eq 2 so 3 un 3 + cr0 0 cr1 1 cr2 2 cr3 3 + cr4 4 cr5 5 cr6 6 cr7 7 + These may be combined arithmetically, as in cr2*4+gt. These are + only supported on the PowerPC, not the POWER. */ +#define PPC_OPERAND_CR (0x10) + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define PPC_OPERAND_GPR (0x20) + +/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0. */ +#define PPC_OPERAND_GPR_0 (0x40) + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define PPC_OPERAND_FPR (0x80) + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_RELATIVE (0x100) + +/* This operand is an absolute branch address. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_ABSOLUTE (0x200) + +/* This operand is optional, and is zero if omitted. This is used for + example, in the optional BF field in the comparison instructions. The + assembler must count the number of operands remaining on the line, + and the number of operands remaining for the opcode, and decide + whether this operand is present or not. The disassembler should + print this operand out only if it is not zero. */ +#define PPC_OPERAND_OPTIONAL (0x400) + +/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand + is omitted, then for the next operand use this operand value plus + 1, ignoring the next operand field for the opcode. This wretched + hack is needed because the Power rotate instructions can take + either 4 or 5 operands. The disassembler should print this operand + out regardless of the PPC_OPERAND_OPTIONAL field. */ +#define PPC_OPERAND_NEXT (0x800) + +/* This operand should be regarded as a negative number for the + purposes of overflow checking (i.e., the normal most negative + number is disallowed and one more than the normal most positive + number is allowed). This flag will only be set for a signed + operand. */ +#define PPC_OPERAND_NEGATIVE (0x1000) + +/* This operand names a vector unit register. The disassembler + prints these with a leading 'v'. */ +#define PPC_OPERAND_VR (0x2000) + +/* This operand is for the DS field in a DS form instruction. */ +#define PPC_OPERAND_DS (0x4000) + +/* This operand is for the DQ field in a DQ form instruction. */ +#define PPC_OPERAND_DQ (0x8000) + +/* Valid range of operand is 0..n rather than 0..n-1. */ +#define PPC_OPERAND_PLUS1 (0x10000) + +/* The POWER and PowerPC assemblers use a few macros. We keep them + with the operands table for simplicity. The macro table is an + array of struct powerpc_macro. */ + +struct powerpc_macro +{ + /* The macro name. */ + const char *name; + + /* The number of operands the macro takes. */ + unsigned int operands; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The values are the + same as those for the struct powerpc_opcode flags field. */ + unsigned long flags; + + /* A format string to turn the macro into a normal instruction. + Each %N in the string is replaced with operand number N (zero + based). */ + const char *format; +}; + +extern const struct powerpc_macro powerpc_macros[]; +extern const int powerpc_num_macros; + +/* ppc-opc.c -- PowerPC opcode list + Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. + If not, see . */ + +/* This file holds the PowerPC opcode table. The opcode table + includes almost all of the extended instruction mnemonics. This + permits the disassembler to use them, and simplifies the assembler + logic, at the cost of increasing the table size. The table is + strictly constant data, so the compiler should be able to put it in + the .text section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* Local insertion and extraction functions. */ + +static unsigned long insert_bat (unsigned long, long, int, const char **); +static long extract_bat (unsigned long, int, int *); +static unsigned long insert_bba (unsigned long, long, int, const char **); +static long extract_bba (unsigned long, int, int *); +static unsigned long insert_bdm (unsigned long, long, int, const char **); +static long extract_bdm (unsigned long, int, int *); +static unsigned long insert_bdp (unsigned long, long, int, const char **); +static long extract_bdp (unsigned long, int, int *); +static unsigned long insert_bo (unsigned long, long, int, const char **); +static long extract_bo (unsigned long, int, int *); +static unsigned long insert_boe (unsigned long, long, int, const char **); +static long extract_boe (unsigned long, int, int *); +static unsigned long insert_fxm (unsigned long, long, int, const char **); +static long extract_fxm (unsigned long, int, int *); +static unsigned long insert_mbe (unsigned long, long, int, const char **); +static long extract_mbe (unsigned long, int, int *); +static unsigned long insert_mb6 (unsigned long, long, int, const char **); +static long extract_mb6 (unsigned long, int, int *); +static long extract_nb (unsigned long, int, int *); +static unsigned long insert_nsi (unsigned long, long, int, const char **); +static long extract_nsi (unsigned long, int, int *); +static unsigned long insert_ral (unsigned long, long, int, const char **); +static unsigned long insert_ram (unsigned long, long, int, const char **); +static unsigned long insert_raq (unsigned long, long, int, const char **); +static unsigned long insert_ras (unsigned long, long, int, const char **); +static unsigned long insert_rbs (unsigned long, long, int, const char **); +static long extract_rbs (unsigned long, int, int *); +static unsigned long insert_sh6 (unsigned long, long, int, const char **); +static long extract_sh6 (unsigned long, int, int *); +static unsigned long insert_spr (unsigned long, long, int, const char **); +static long extract_spr (unsigned long, int, int *); +static unsigned long insert_sprg (unsigned long, long, int, const char **); +static long extract_sprg (unsigned long, int, int *); +static unsigned long insert_tbr (unsigned long, long, int, const char **); +static long extract_tbr (unsigned long, int, int *); + +/* The operands table. + + The fields are bitm, shift, insert, extract, flags. + + We used to put parens around the various additions, like the one + for BA just below. However, that caused trouble with feeble + compilers with a limit on depth of a parenthesized expression, like + (reportedly) the compiler in Microsoft Developer Studio 5. So we + omit the parens, since the macros are never used in a context where + the addition will be ambiguous. */ + +const struct powerpc_operand powerpc_operands[] = +{ + /* The zero index is used to indicate the end of the list of + operands. */ +#define UNUSED 0 + { 0, 0, NULL, NULL, 0 }, + + /* The BA field in an XL form instruction. */ +#define BA UNUSED + 1 + /* The BI field in a B form or XL form instruction. */ +#define BI BA +#define BI_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR }, + + /* The BA field in an XL form instruction when it must be the same + as the BT field in the same instruction. */ +#define BAT BA + 1 + { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, + + /* The BB field in an XL form instruction. */ +#define BB BAT + 1 +#define BB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR }, + + /* The BB field in an XL form instruction when it must be the same + as the BA field in the same instruction. */ +#define BBA BB + 1 + { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, + + /* The BD field in a B form instruction. The lower two bits are + forced to zero. */ +#define BD BBA + 1 + { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when absolute addressing is + used. */ +#define BDA BD + 1 + { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDM BDA + 1 + { 0xfffc, 0, insert_bdm, extract_bdm, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used + and absolute address is used. */ +#define BDMA BDM + 1 + { 0xfffc, 0, insert_bdm, extract_bdm, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDP BDMA + 1 + { 0xfffc, 0, insert_bdp, extract_bdp, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used + and absolute addressing is used. */ +#define BDPA BDP + 1 + { 0xfffc, 0, insert_bdp, extract_bdp, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BF field in an X or XL form instruction. */ +#define BF BDPA + 1 + /* The CRFD field in an X form instruction. */ +#define CRFD BF + { 0x7, 23, NULL, NULL, PPC_OPERAND_CR }, + + /* The BF field in an X or XL form instruction. */ +#define BFF BF + 1 + { 0x7, 23, NULL, NULL, 0 }, + + /* An optional BF field. This is used for comparison instructions, + in which an omitted BF field is taken as zero. */ +#define OBF BFF + 1 + { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The BFA field in an X or XL form instruction. */ +#define BFA OBF + 1 + { 0x7, 18, NULL, NULL, PPC_OPERAND_CR }, + + /* The BO field in a B form instruction. Certain values are + illegal. */ +#define BO BFA + 1 +#define BO_MASK (0x1f << 21) + { 0x1f, 21, insert_bo, extract_bo, 0 }, + + /* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. */ +#define BOE BO + 1 + { 0x1e, 21, insert_boe, extract_boe, 0 }, + +#define BH BOE + 1 + { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The BT field in an X or XL form instruction. */ +#define BT BH + 1 + { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR }, + + /* The condition register number portion of the BI field in a B form + or XL form instruction. This is used for the extended + conditional branch mnemonics, which set the lower two bits of the + BI field. This field is optional. */ +#define CR BT + 1 + { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The CRB field in an X form instruction. */ +#define CRB CR + 1 + /* The MB field in an M form instruction. */ +#define MB CRB +#define MB_MASK (0x1f << 6) + { 0x1f, 6, NULL, NULL, 0 }, + + /* The CRFS field in an X form instruction. */ +#define CRFS CRB + 1 + { 0x7, 0, NULL, NULL, PPC_OPERAND_CR }, + + /* The CT field in an X form instruction. */ +#define CT CRFS + 1 + /* The MO field in an mbar instruction. */ +#define MO CT + { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The D field in a D form instruction. This is a displacement off + a register, and implies that the next operand is a register in + parentheses. */ +#define D CT + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DE field in a DE form instruction. This is like D, but is 12 + bits only. */ +#define DE D + 1 + { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DES field in a DES form instruction. This is like DS, but is 14 + bits only (12 stored.) */ +#define DES DE + 1 + { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DQ field in a DQ form instruction. This is like D, but the + lower four bits are forced to zero. */ +#define DQ DES + 1 + { 0xfff0, 0, NULL, NULL, + PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ }, + + /* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ +#undef DS +#define DS DQ + 1 + { 0xfffc, 0, NULL, NULL, + PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS }, + + /* The E field in a wrteei instruction. */ +#define E DS + 1 + { 0x1, 15, NULL, NULL, 0 }, + + /* The FL1 field in a POWER SC form instruction. */ +#define FL1 E + 1 + /* The U field in an X form instruction. */ +#define U FL1 + { 0xf, 12, NULL, NULL, 0 }, + + /* The FL2 field in a POWER SC form instruction. */ +#define FL2 FL1 + 1 + { 0x7, 2, NULL, NULL, 0 }, + + /* The FLM field in an XFL form instruction. */ +#define FLM FL2 + 1 + { 0xff, 17, NULL, NULL, 0 }, + + /* The FRA field in an X or A form instruction. */ +#define FRA FLM + 1 +#define FRA_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRB field in an X or A form instruction. */ +#define FRB FRA + 1 +#define FRB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRC field in an A form instruction. */ +#define FRC FRB + 1 +#define FRC_MASK (0x1f << 6) + { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FRS field in an X form instruction or the FRT field in a D, X + or A form instruction. */ +#define FRS FRC + 1 +#define FRT FRS + { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR }, + + /* The FXM field in an XFX instruction. */ +#define FXM FRS + 1 + { 0xff, 12, insert_fxm, extract_fxm, 0 }, + + /* Power4 version for mfcr. */ +#define FXM4 FXM + 1 + { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL }, + + /* The L field in a D or X form instruction. */ +#define L FXM4 + 1 + { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The LEV field in a POWER SVC form instruction. */ +#define SVC_LEV L + 1 + { 0x7f, 5, NULL, NULL, 0 }, + + /* The LEV field in an SC form instruction. */ +#define LEV SVC_LEV + 1 + { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The LI field in an I form instruction. The lower two bits are + forced to zero. */ +#define LI LEV + 1 + { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The LI field in an I form instruction when used as an absolute + address. */ +#define LIA LI + 1 + { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The LS field in an X (sync) form instruction. */ +#define LS LIA + 1 + { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The ME field in an M form instruction. */ +#define ME LS + 1 +#define ME_MASK (0x1f << 1) + { 0x1f, 1, NULL, NULL, 0 }, + + /* The MB and ME fields in an M form instruction expressed a single + operand which is a bitmask indicating which bits to select. This + is a two operand form using PPC_OPERAND_NEXT. See the + description in opcode/ppc.h for what this means. */ +#define MBE ME + 1 + { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, + { -1, 0, insert_mbe, extract_mbe, 0 }, + + /* The MB or ME field in an MD or MDS form instruction. The high + bit is wrapped to the low end. */ +#define MB6 MBE + 2 +#define ME6 MB6 +#define MB6_MASK (0x3f << 5) + { 0x3f, 5, insert_mb6, extract_mb6, 0 }, + + /* The NB field in an X form instruction. The value 32 is stored as + 0. */ +#define NB MB6 + 1 + { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 }, + + /* The NSI field in a D form instruction. This is the same as the + SI field, only negated. */ +#define NSI NB + 1 + { 0xffff, 0, insert_nsi, extract_nsi, + PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, + + /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */ +#define RA NSI + 1 +#define RA_MASK (0x1f << 16) + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR }, + + /* As above, but 0 in the RA field means zero, not r0. */ +#define RA0 RA + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in the DQ form lq instruction, which has special + value restrictions. */ +#define RAQ RA0 + 1 + { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ +#define RAL RAQ + 1 + { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in an lmw instruction, which has special value + restrictions. */ +#define RAM RAL + 1 + { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ +#define RAS RAM + 1 + { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 }, + + /* The RA field of the tlbwe instruction, which is optional. */ +#define RAOPT RAS + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, + + /* The RB field in an X, XO, M, or MDS form instruction. */ +#define RB RAOPT + 1 +#define RB_MASK (0x1f << 11) + { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR }, + + /* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. */ +#define RBS RB + 1 + { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, + + /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form + instruction or the RT field in a D, DS, X, XFX or XO form + instruction. */ +#define RS RBS + 1 +#define RT RS +#define RT_MASK (0x1f << 21) + { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR }, + + /* The RS and RT fields of the DS form stq instruction, which have + special value restrictions. */ +#define RSQ RS + 1 +#define RTQ RSQ + { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 }, + + /* The RS field of the tlbwe instruction, which is optional. */ +#define RSO RSQ + 1 +#define RTO RSO + { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, + + /* The SH field in an X or M form instruction. */ +#define SH RSO + 1 +#define SH_MASK (0x1f << 11) + /* The other UIMM field in a EVX form instruction. */ +#define EVUIMM SH + { 0x1f, 11, NULL, NULL, 0 }, + + /* The SH field in an MD form instruction. This is split. */ +#define SH6 SH + 1 +#define SH6_MASK ((0x1f << 11) | (1 << 1)) + { 0x3f, -1, insert_sh6, extract_sh6, 0 }, + + /* The SH field of the tlbwe instruction, which is optional. */ +#define SHO SH6 + 1 + { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The SI field in a D form instruction. */ +#define SI SHO + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED }, + + /* The SI field in a D form instruction when we accept a wide range + of positive values. */ +#define SISIGNOPT SI + 1 + { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, + + /* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ +#define SPR SISIGNOPT + 1 +#define PMR SPR +#define SPR_MASK (0x3ff << 11) + { 0x3ff, 11, insert_spr, extract_spr, 0 }, + + /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ +#define SPRBAT SPR + 1 +#define SPRBAT_MASK (0x3 << 17) + { 0x3, 17, NULL, NULL, 0 }, + + /* The SPRG register number in an XFX form m[ft]sprg instruction. */ +#define SPRG SPRBAT + 1 + { 0x1f, 16, insert_sprg, extract_sprg, 0 }, + + /* The SR field in an X form instruction. */ +#define SR SPRG + 1 + { 0xf, 16, NULL, NULL, 0 }, + + /* The STRM field in an X AltiVec form instruction. */ +#define STRM SR + 1 + { 0x3, 21, NULL, NULL, 0 }, + + /* The SV field in a POWER SC form instruction. */ +#define SV STRM + 1 + { 0x3fff, 2, NULL, NULL, 0 }, + + /* The TBR field in an XFX form instruction. This is like the SPR + field, but it is optional. */ +#define TBR SV + 1 + { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, + + /* The TO field in a D or X form instruction. */ +#define TO TBR + 1 +#define TO_MASK (0x1f << 21) + { 0x1f, 21, NULL, NULL, 0 }, + + /* The UI field in a D form instruction. */ +#define UI TO + 1 + { 0xffff, 0, NULL, NULL, 0 }, + + /* The VA field in a VA, VX or VXR form instruction. */ +#define VA UI + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR }, + + /* The VB field in a VA, VX or VXR form instruction. */ +#define VB VA + 1 + { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR }, + + /* The VC field in a VA form instruction. */ +#define VC VB + 1 + { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR }, + + /* The VD or VS field in a VA, VX, VXR or X form instruction. */ +#define VD VC + 1 +#define VS VD + { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR }, + + /* The SIMM field in a VX form instruction. */ +#define SIMM VD + 1 + { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED}, + + /* The UIMM field in a VX form instruction, and TE in Z form. */ +#define UIMM SIMM + 1 +#define TE UIMM + { 0x1f, 16, NULL, NULL, 0 }, + + /* The SHB field in a VA form instruction. */ +#define SHB UIMM + 1 + { 0xf, 6, NULL, NULL, 0 }, + + /* The other UIMM field in a half word EVX form instruction. */ +#define EVUIMM_2 SHB + 1 + { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The other UIMM field in a word EVX form instruction. */ +#define EVUIMM_4 EVUIMM_2 + 1 + { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The other UIMM field in a double EVX form instruction. */ +#define EVUIMM_8 EVUIMM_4 + 1 + { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS }, + + /* The WS field. */ +#define WS EVUIMM_8 + 1 + { 0x7, 11, NULL, NULL, 0 }, + + /* The L field in an mtmsrd or A form instruction or W in an X form. */ +#define A_L WS + 1 +#define W A_L + { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL }, + +#define RMC A_L + 1 + { 0x3, 9, NULL, NULL, 0 }, + +#define R RMC + 1 + { 0x1, 16, NULL, NULL, 0 }, + +#define SP R + 1 + { 0x3, 19, NULL, NULL, 0 }, + +#define S SP + 1 + { 0x1, 20, NULL, NULL, 0 }, + + /* SH field starting at bit position 16. */ +#define SH16 S + 1 + /* The DCM and DGM fields in a Z form instruction. */ +#define DCM SH16 +#define DGM DCM + { 0x3f, 10, NULL, NULL, 0 }, + + /* The EH field in larx instruction. */ +#define EH SH16 + 1 + { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL }, + + /* The L field in an mtfsf or XFL form instruction. */ +#define XFL_L EH + 1 + { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL}, +}; + +const unsigned int num_powerpc_operands = (sizeof (powerpc_operands) + / sizeof (powerpc_operands[0])); + +/* The functions used to insert and extract complicated operands. */ + +/* The BA field in an XL form instruction when it must be the same as + the BT field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BT field into the BA field, + and the extraction function just checks that the fields are the + same. */ + +static unsigned long +insert_bat (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static long +extract_bat (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BB field in an XL form instruction when it must be the same as + the BA field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BA field into the BB field, + and the extraction function just checks that the fields are the + same. */ + +static unsigned long +insert_bba (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 16) & 0x1f) << 11); +} + +static long +extract_bba (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BD field in a B form instruction when the - modifier is used. + This modifier means that the branch is not expected to be taken. + For chips built to versions of the architecture prior to version 2 + (ie. not Power4 compatible), we set the y bit of the BO field to 1 + if the offset is negative. When extracting, we require that the y + bit be 1 and that the offset be positive, since if the y bit is 0 + we just want to print the normal form of the instruction. + Power4 compatible targets use two bits, "a", and "t", instead of + the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable, + "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001 + in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000 + for branch on CTR. We only handle the taken/not-taken hint here. + Note that we don't relax the conditions tested here when + disassembling with -Many because insns using extract_bdm and + extract_bdp always occur in pairs. One or the other will always + be valid. */ + +static unsigned long +insert_bdm (unsigned long insn, + long value, + int dialect, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if ((value & 0x8000) != 0) + insn |= 1 << 21; + } + else + { + if ((insn & (0x14 << 21)) == (0x04 << 21)) + insn |= 0x02 << 21; + else if ((insn & (0x14 << 21)) == (0x10 << 21)) + insn |= 0x08 << 21; + } + return insn | (value & 0xfffc); +} + +static long +extract_bdm (unsigned long insn, + int dialect, + int *invalid) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0)) + *invalid = 1; + } + else + { + if ((insn & (0x17 << 21)) != (0x06 << 21) + && (insn & (0x1d << 21)) != (0x18 << 21)) + *invalid = 1; + } + + return ((insn & 0xfffc) ^ 0x8000) - 0x8000; +} + +/* The BD field in a B form instruction when the + modifier is used. + This is like BDM, above, except that the branch is expected to be + taken. */ + +static unsigned long +insert_bdp (unsigned long insn, + long value, + int dialect, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if ((value & 0x8000) == 0) + insn |= 1 << 21; + } + else + { + if ((insn & (0x14 << 21)) == (0x04 << 21)) + insn |= 0x03 << 21; + else if ((insn & (0x14 << 21)) == (0x10 << 21)) + insn |= 0x09 << 21; + } + return insn | (value & 0xfffc); +} + +static long +extract_bdp (unsigned long insn, + int dialect, + int *invalid) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0)) + *invalid = 1; + } + else + { + if ((insn & (0x17 << 21)) != (0x07 << 21) + && (insn & (0x1d << 21)) != (0x19 << 21)) + *invalid = 1; + } + + return ((insn & 0xfffc) ^ 0x8000) - 0x8000; +} + +/* Check for legal values of a BO field. */ + +static int +valid_bo (long value, int dialect, int extract) +{ + if ((dialect & PPC_OPCODE_POWER4) == 0) + { + int valid; + /* Certain encodings have bits that are required to be zero. + These are (z must be zero, y may be anything): + 001zy + 011zy + 1z00y + 1z01y + 1z1zz + */ + switch (value & 0x14) + { + default: + case 0: + valid = 1; + break; + case 0x4: + valid = (value & 0x2) == 0; + break; + case 0x10: + valid = (value & 0x8) == 0; + break; + case 0x14: + valid = value == 0x14; + break; + } + /* When disassembling with -Many, accept power4 encodings too. */ + if (valid + || (dialect & PPC_OPCODE_ANY) == 0 + || !extract) + return valid; + } + + /* Certain encodings have bits that are required to be zero. + These are (z must be zero, a & t may be anything): + 0000z + 0001z + 0100z + 0101z + 001at + 011at + 1a00t + 1a01t + 1z1zz + */ + if ((value & 0x14) == 0) + return (value & 0x1) == 0; + else if ((value & 0x14) == 0x14) + return value == 0x14; + else + return 1; +} + +/* The BO field in a B form instruction. Warn about attempts to set + the field to an illegal value. */ + +static unsigned long +insert_bo (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + if (!valid_bo (value, dialect, 0)) + *errmsg = _("invalid conditional option"); + return insn | ((value & 0x1f) << 21); +} + +static long +extract_bo (unsigned long insn, + int dialect, + int *invalid) +{ + long value; + + value = (insn >> 21) & 0x1f; + if (!valid_bo (value, dialect, 1)) + *invalid = 1; + return value; +} + +/* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. When + extracting it, we force it to be even. */ + +static unsigned long +insert_boe (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + if (!valid_bo (value, dialect, 0)) + *errmsg = _("invalid conditional option"); + else if ((value & 1) != 0) + *errmsg = _("attempt to set y bit when using + or - modifier"); + + return insn | ((value & 0x1f) << 21); +} + +static long +extract_boe (unsigned long insn, + int dialect, + int *invalid) +{ + long value; + + value = (insn >> 21) & 0x1f; + if (!valid_bo (value, dialect, 1)) + *invalid = 1; + return value & 0x1e; +} + +/* FXM mask in mfcr and mtcrf instructions. */ + +static unsigned long +insert_fxm (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + /* If we're handling the mfocrf and mtocrf insns ensure that exactly + one bit of the mask field is set. */ + if ((insn & (1 << 20)) != 0) + { + if (value == 0 || (value & -value) != value) + { + *errmsg = _("invalid mask field"); + value = 0; + } + } + + /* If the optional field on mfcr is missing that means we want to use + the old form of the instruction that moves the whole cr. In that + case we'll have VALUE zero. There doesn't seem to be a way to + distinguish this from the case where someone writes mfcr %r3,0. */ + else if (value == 0) + ; + + /* If only one bit of the FXM field is set, we can use the new form + of the instruction, which is faster. Unlike the Power4 branch hint + encoding, this is not backward compatible. Do not generate the + new form unless -mpower4 has been given, or -many and the two + operand form of mfcr was used. */ + else if ((value & -value) == value + && ((dialect & PPC_OPCODE_POWER4) != 0 + || ((dialect & PPC_OPCODE_ANY) != 0 + && (insn & (0x3ff << 1)) == 19 << 1))) + insn |= 1 << 20; + + /* Any other value on mfcr is an error. */ + else if ((insn & (0x3ff << 1)) == 19 << 1) + { + *errmsg = _("ignoring invalid mfcr mask"); + value = 0; + } + + return insn | ((value & 0xff) << 12); +} + +static long +extract_fxm (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + long mask = (insn >> 12) & 0xff; + + /* Is this a Power4 insn? */ + if ((insn & (1 << 20)) != 0) + { + /* Exactly one bit of MASK should be set. */ + if (mask == 0 || (mask & -mask) != mask) + *invalid = 1; + } + + /* Check that non-power4 form of mfcr has a zero MASK. */ + else if ((insn & (0x3ff << 1)) == 19 << 1) + { + if (mask != 0) + *invalid = 1; + } + + return mask; +} + +/* The MB and ME fields in an M form instruction expressed as a single + operand which is itself a bitmask. The extraction function always + marks it as invalid, since we never want to recognize an + instruction which uses a field of this type. */ + +static unsigned long +insert_mbe (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + unsigned long uval, mask; + int mb, me, mx, count, last; + + uval = value; + + if (uval == 0) + { + *errmsg = _("illegal bitmask"); + return insn; + } + + mb = 0; + me = 32; + if ((uval & 1) != 0) + last = 1; + else + last = 0; + count = 0; + + /* mb: location of last 0->1 transition */ + /* me: location of last 1->0 transition */ + /* count: # transitions */ + + for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1) + { + if ((uval & mask) && !last) + { + ++count; + mb = mx; + last = 1; + } + else if (!(uval & mask) && last) + { + ++count; + me = mx; + last = 0; + } + } + if (me == 0) + me = 32; + + if (count != 2 && (count != 0 || ! last)) + *errmsg = _("illegal bitmask"); + + return insn | (mb << 6) | ((me - 1) << 1); +} + +static long +extract_mbe (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + long ret; + int mb, me; + int i; + + *invalid = 1; + + mb = (insn >> 6) & 0x1f; + me = (insn >> 1) & 0x1f; + if (mb < me + 1) + { + ret = 0; + for (i = mb; i <= me; i++) + ret |= 1L << (31 - i); + } + else if (mb == me + 1) + ret = ~0; + else /* (mb > me + 1) */ + { + ret = ~0; + for (i = me + 1; i < mb; i++) + ret &= ~(1L << (31 - i)); + } + return ret; +} + +/* The MB or ME field in an MD or MDS form instruction. The high bit + is wrapped to the low end. */ + +static unsigned long +insert_mb6 (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 6) | (value & 0x20); +} + +static long +extract_mb6 (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 6) & 0x1f) | (insn & 0x20); +} + +/* The NB field in an X form instruction. The value 32 is stored as + 0. */ + +static long +extract_nb (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + long ret; + + ret = (insn >> 11) & 0x1f; + if (ret == 0) + ret = 32; + return ret; +} + +/* The NSI field in a D form instruction. This is the same as the SI + field, only negated. The extraction function always marks it as + invalid, since we never want to recognize an instruction which uses + a field of this type. */ + +static unsigned long +insert_nsi (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (-value & 0xffff); +} + +static long +extract_nsi (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + *invalid = 1; + return -(((insn & 0xffff) ^ 0x8000) - 0x8000); +} + +/* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ + +static unsigned long +insert_ral (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if (value == 0 + || (unsigned long) value == ((insn >> 21) & 0x1f)) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in an lmw instruction, which has special value + restrictions. */ + +static unsigned long +insert_ram (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if ((unsigned long) value >= ((insn >> 21) & 0x1f)) + *errmsg = _("index register in load range"); + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in the DQ form lq instruction, which has special + value restrictions. */ + +static unsigned long +insert_raq (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + long rtvalue = (insn & RT_MASK) >> 21; + + if (value == rtvalue) + *errmsg = _("source and target register operands must be different"); + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ + +static unsigned long +insert_ras (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg) +{ + if (value == 0) + *errmsg = _("invalid register operand when updating"); + return insn | ((value & 0x1f) << 16); +} + +/* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. This operand is marked FAKE. The insertion + function just copies the BT field into the BA field, and the + extraction function just checks that the fields are the same. */ + +static unsigned long +insert_rbs (unsigned long insn, + long value ATTRIBUTE_UNUSED, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 11); +} + +static long +extract_rbs (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid) +{ + if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The SH field in an MD form instruction. This is split. */ + +static unsigned long +insert_sh6 (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); +} + +static long +extract_sh6 (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); +} + +/* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ + +static unsigned long +insert_spr (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_spr (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); +} + +/* Some dialects have 8 SPRG registers instead of the standard 4. */ + +static unsigned long +insert_sprg (unsigned long insn, + long value, + int dialect, + const char **errmsg) +{ + /* This check uses PPC_OPCODE_403 because PPC405 is later defined + as a synonym. If ever a 405 specific dialect is added this + check should use that instead. */ + if (value > 7 + || (value > 3 + && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) + *errmsg = _("invalid sprg number"); + + /* If this is mfsprg4..7 then use spr 260..263 which can be read in + user mode. Anything else must use spr 272..279. */ + if (value <= 3 || (insn & 0x100) != 0) + value |= 0x10; + + return insn | ((value & 0x17) << 16); +} + +static long +extract_sprg (unsigned long insn, + int dialect, + int *invalid) +{ + unsigned long val = (insn >> 16) & 0x1f; + + /* mfsprg can use 260..263 and 272..279. mtsprg only uses spr 272..279 + If not BOOKE or 405, then both use only 272..275. */ + if (val <= 3 + || (val < 0x10 && (insn & 0x100) != 0) + || (val - 0x10 > 3 + && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) + *invalid = 1; + return val & 7; +} + +/* The TBR field in an XFX instruction. This is just like SPR, but it + is optional. When TBR is omitted, it must be inserted as 268 (the + magic number of the TB register). These functions treat 0 + (indicating an omitted optional operand) as 268. This means that + ``mftb 4,0'' is not handled correctly. This does not matter very + much, since the architecture manual does not define mftb as + accepting any values other than 268 or 269. */ + +#define TB (268) + +static unsigned long +insert_tbr (unsigned long insn, + long value, + int dialect ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + if (value == 0) + value = TB; + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_tbr (unsigned long insn, + int dialect ATTRIBUTE_UNUSED, + int *invalid ATTRIBUTE_UNUSED) +{ + long ret; + + ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); + if (ret == TB) + ret = 0; + return ret; +} + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26) +#define OP_MASK OP (0x3f) + +/* The main opcode combined with a trap code in the TO field of a D + form instruction. Used for extended mnemonics for the trap + instructions. */ +#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21)) +#define OPTO_MASK (OP_MASK | TO_MASK) + +/* The main opcode combined with a comparison size bit in the L field + of a D form or X form instruction. Used for extended mnemonics for + the comparison instructions. */ +#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21)) +#define OPL_MASK OPL (0x3f,1) + +/* An A form instruction. */ +#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1)) +#define A_MASK A (0x3f, 0x1f, 1) + +/* An A_MASK with the FRB field fixed. */ +#define AFRB_MASK (A_MASK | FRB_MASK) + +/* An A_MASK with the FRC field fixed. */ +#define AFRC_MASK (A_MASK | FRC_MASK) + +/* An A_MASK with the FRA and FRC fields fixed. */ +#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) + +/* An AFRAFRC_MASK, but with L bit clear. */ +#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16)) + +/* A B form instruction. */ +#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1)) +#define B_MASK B (0x3f, 1, 1) + +/* A B form instruction setting the BO field. */ +#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) +#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) + +/* A BBO_MASK with the y bit of the BO field removed. This permits + matching a conditional branch regardless of the setting of the y + bit. Similarly for the 'at' bits used for power4 branch hints. */ +#define Y_MASK (((unsigned long) 1) << 21) +#define AT1_MASK (((unsigned long) 3) << 21) +#define AT2_MASK (((unsigned long) 9) << 21) +#define BBOY_MASK (BBO_MASK &~ Y_MASK) +#define BBOAT_MASK (BBO_MASK &~ AT1_MASK) + +/* A B form instruction setting the BO field and the condition bits of + the BI field. */ +#define BBOCB(op, bo, cb, aa, lk) \ + (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16)) +#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) + +/* A BBOCB_MASK with the y bit of the BO field removed. */ +#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) +#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK) +#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK) + +/* A BBOYCB_MASK in which the BI field is fixed. */ +#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) +#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) + +/* An Context form instruction. */ +#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7)) +#define CTX_MASK CTX(0x3f, 0x7) + +/* An User Context form instruction. */ +#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) +#define UCTX_MASK UCTX(0x3f, 0x1f) + +/* The main opcode mask with the RA field clear. */ +#define DRA_MASK (OP_MASK | RA_MASK) + +/* A DS form instruction. */ +#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) +#define DS_MASK DSO (0x3f, 3) + +/* A DE form instruction. */ +#define DEO(op, xop) (OP (op) | ((xop) & 0xf)) +#define DE_MASK DEO (0x3e, 0xf) + +/* An EVSEL form instruction. */ +#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3) +#define EVSEL_MASK EVSEL(0x3f, 0xff) + +/* An M form instruction. */ +#define M(op, rc) (OP (op) | ((rc) & 1)) +#define M_MASK M (0x3f, 1) + +/* An M form instruction with the ME field specified. */ +#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1)) + +/* An M_MASK with the MB and ME fields fixed. */ +#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) + +/* An M_MASK with the SH and ME fields fixed. */ +#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) + +/* An MD form instruction. */ +#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1)) +#define MD_MASK MD (0x3f, 0x7, 1) + +/* An MD_MASK with the MB field fixed. */ +#define MDMB_MASK (MD_MASK | MB6_MASK) + +/* An MD_MASK with the SH field fixed. */ +#define MDSH_MASK (MD_MASK | SH6_MASK) + +/* An MDS form instruction. */ +#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1)) +#define MDS_MASK MDS (0x3f, 0xf, 1) + +/* An MDS_MASK with the MB field fixed. */ +#define MDSMB_MASK (MDS_MASK | MB6_MASK) + +/* An SC form instruction. */ +#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) +#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) + +/* An VX form instruction. */ +#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) + +/* The mask for an VX form instruction. */ +#define VX_MASK VX(0x3f, 0x7ff) + +/* An VA form instruction. */ +#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) + +/* The mask for an VA form instruction. */ +#define VXA_MASK VXA(0x3f, 0x3f) + +/* An VXR form instruction. */ +#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) + +/* The mask for a VXR form instruction. */ +#define VXR_MASK VXR(0x3f, 0x3ff, 1) + +/* An X form instruction. */ +#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) + +/* A Z form instruction. */ +#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1)) + +/* An X form instruction with the RC bit specified. */ +#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) + +/* A Z form instruction with the RC bit specified. */ +#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1)) + +/* The mask for an X form instruction. */ +#define X_MASK XRC (0x3f, 0x3ff, 1) + +/* The mask for a Z form instruction. */ +#define Z_MASK ZRC (0x3f, 0x1ff, 1) +#define Z2_MASK ZRC (0x3f, 0xff, 1) + +/* An X_MASK with the RA field fixed. */ +#define XRA_MASK (X_MASK | RA_MASK) + +/* An XRA_MASK with the W field clear. */ +#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16)) + +/* An X_MASK with the RB field fixed. */ +#define XRB_MASK (X_MASK | RB_MASK) + +/* An X_MASK with the RT field fixed. */ +#define XRT_MASK (X_MASK | RT_MASK) + +/* An XRT_MASK mask with the L bits clear. */ +#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21)) + +/* An X_MASK with the RA and RB fields fixed. */ +#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) + +/* An XRARB_MASK, but with the L bit clear. */ +#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16)) + +/* An X_MASK with the RT and RA fields fixed. */ +#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) + +/* An XRTRA_MASK, but with L bit clear. */ +#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21)) + +/* An X form instruction with the L bit specified. */ +#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21)) + +/* The mask for an X form comparison instruction. */ +#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22)) + +/* The mask for an X form comparison instruction with the L field + fixed. */ +#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21)) + +/* An X form trap instruction with the TO field specified. */ +#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21)) +#define XTO_MASK (X_MASK | TO_MASK) + +/* An X form tlb instruction with the SH field specified. */ +#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11)) +#define XTLB_MASK (X_MASK | SH_MASK) + +/* An X form sync instruction. */ +#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21)) + +/* An X form sync instruction with everything filled in except the LS field. */ +#define XSYNC_MASK (0xff9fffff) + +/* An X_MASK, but with the EH bit clear. */ +#define XEH_MASK (X_MASK & ~((unsigned long )1)) + +/* An X form AltiVec dss instruction. */ +#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25)) +#define XDSS_MASK XDSS(0x3f, 0x3ff, 1) + +/* An XFL form instruction. */ +#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1)) +#define XFL_MASK XFL (0x3f, 0x3ff, 1) + +/* An X form isel instruction. */ +#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1)) +#define XISEL_MASK XISEL(0x3f, 0x1f) + +/* An XL form instruction with the LK field set to 0. */ +#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) + +/* An XL form instruction which uses the LK field. */ +#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) + +/* The mask for an XL form instruction. */ +#define XL_MASK XLLK (0x3f, 0x3ff, 1) + +/* An XL form instruction which explicitly sets the BO field. */ +#define XLO(op, bo, xop, lk) \ + (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) +#define XLO_MASK (XL_MASK | BO_MASK) + +/* An XL form instruction which explicitly sets the y bit of the BO + field. */ +#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21)) +#define XLYLK_MASK (XL_MASK | Y_MASK) + +/* An XL form instruction which sets the BO field and the condition + bits of the BI field. */ +#define XLOCB(op, bo, cb, xop, lk) \ + (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16)) +#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) + +/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ +#define XLBB_MASK (XL_MASK | BB_MASK) +#define XLYBB_MASK (XLYLK_MASK | BB_MASK) +#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) + +/* A mask for branch instructions using the BH field. */ +#define XLBH_MASK (XL_MASK | (0x1c << 11)) + +/* An XL_MASK with the BO and BB fields fixed. */ +#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) + +/* An XL_MASK with the BO, BI and BB fields fixed. */ +#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) + +/* An XO form instruction. */ +#define XO(op, xop, oe, rc) \ + (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1)) +#define XO_MASK XO (0x3f, 0x1ff, 1, 1) + +/* An XO_MASK with the RB field fixed. */ +#define XORB_MASK (XO_MASK | RB_MASK) + +/* An XS form instruction. */ +#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1)) +#define XS_MASK XS (0x3f, 0x1ff, 1) + +/* A mask for the FXM version of an XFX form instruction. */ +#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20)) + +/* An XFX form instruction with the FXM field filled in. */ +#define XFXM(op, xop, fxm, p4) \ + (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \ + | ((unsigned long)(p4) << 20)) + +/* An XFX form instruction with the SPR field filled in. */ +#define XSPR(op, xop, spr) \ + (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6)) +#define XSPR_MASK (X_MASK | SPR_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRBAT field. */ +#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRG field. */ +#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16)) + +/* An X form instruction with everything filled in except the E field. */ +#define XE_MASK (0xffff7fff) + +/* An X form user context instruction. */ +#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) +#define XUC_MASK XUC(0x3f, 0x1f) + +/* The BO encodings used in extended conditional branch mnemonics. */ +#define BODNZF (0x0) +#define BODNZFP (0x1) +#define BODZF (0x2) +#define BODZFP (0x3) +#define BODNZT (0x8) +#define BODNZTP (0x9) +#define BODZT (0xa) +#define BODZTP (0xb) + +#define BOF (0x4) +#define BOFP (0x5) +#define BOFM4 (0x6) +#define BOFP4 (0x7) +#define BOT (0xc) +#define BOTP (0xd) +#define BOTM4 (0xe) +#define BOTP4 (0xf) + +#define BODNZ (0x10) +#define BODNZP (0x11) +#define BODZ (0x12) +#define BODZP (0x13) +#define BODNZM4 (0x18) +#define BODNZP4 (0x19) +#define BODZM4 (0x1a) +#define BODZP4 (0x1b) + +#define BOU (0x14) + +/* The BI condition bit encodings used in extended conditional branch + mnemonics. */ +#define CBLT (0) +#define CBGT (1) +#define CBEQ (2) +#define CBSO (3) + +/* The TO encodings used in extended trap mnemonics. */ +#define TOLGT (0x1) +#define TOLLT (0x2) +#define TOEQ (0x4) +#define TOLGE (0x5) +#define TOLNL (0x5) +#define TOLLE (0x6) +#define TOLNG (0x6) +#define TOGT (0x8) +#define TOGE (0xc) +#define TONL (0xc) +#define TOLT (0x10) +#define TOLE (0x14) +#define TONG (0x14) +#define TONE (0x18) +#define TOU (0x1f) + +/* Smaller names for the flags so each entry in the opcodes table will + fit on a single line. */ +#undef PPC +#define PPC PPC_OPCODE_PPC +#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON +#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM +#define POWER4 PPC_OPCODE_POWER4 +#define POWER5 PPC_OPCODE_POWER5 +#define POWER6 PPC_OPCODE_POWER6 +#define CELL PPC_OPCODE_CELL +#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC +#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC +#define PPC403 PPC_OPCODE_403 +#define PPC405 PPC403 +#define PPC440 PPC_OPCODE_440 +#define PPC750 PPC +#define PPC860 PPC +#define PPCVEC PPC_OPCODE_ALTIVEC +#define POWER PPC_OPCODE_POWER +#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2 +#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 +#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_32 +#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON +#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32 +#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601 +#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON +#define MFDEC1 PPC_OPCODE_POWER +#define MFDEC2 PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE +#define BOOKE PPC_OPCODE_BOOKE +#define BOOKE64 PPC_OPCODE_BOOKE64 +#define CLASSIC PPC_OPCODE_CLASSIC +#define PPCE300 PPC_OPCODE_E300 +#define PPCSPE PPC_OPCODE_SPE +#define PPCISEL PPC_OPCODE_ISEL +#define PPCEFS PPC_OPCODE_EFS +#define PPCBRLK PPC_OPCODE_BRLOCK +#define PPCPMR PPC_OPCODE_PMR +#define PPCCHLK PPC_OPCODE_CACHELCK +#define PPCCHLK64 PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64 +#define PPCRFMCI PPC_OPCODE_RFMCI + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK FLAGS { OPERANDS } + + NAME is the name of the instruction. + OPCODE is the instruction opcode. + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + FLAGS are flags indicated what processors support the instruction. + OPERANDS is the list of operands. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. It is also + sorted by major opcode. */ + +const struct powerpc_opcode powerpc_opcodes[] = { +{ "attn", X(0,256), X_MASK, POWER4, { 0 } }, +{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC64, { RA, SI } }, +{ "tdi", OP(2), OP_MASK, PPC64, { TO, RA, SI } }, + +{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tllti", OPTO(3,TOLLT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "teqi", OPTO(3,TOEQ), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tllei", OPTO(3,TOLLE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tgti", OPTO(3,TOGT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tgei", OPTO(3,TOGE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twnli", OPTO(3,TONL), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tnli", OPTO(3,TONL), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlti", OPTO(3,TOLT), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tlei", OPTO(3,TOLE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twngi", OPTO(3,TONG), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tngi", OPTO(3,TONG), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twnei", OPTO(3,TONE), OPTO_MASK, PPCCOM, { RA, SI } }, +{ "tnei", OPTO(3,TONE), OPTO_MASK, PWRCOM, { RA, SI } }, +{ "twi", OP(3), OP_MASK, PPCCOM, { TO, RA, SI } }, +{ "ti", OP(3), OP_MASK, PWRCOM, { TO, RA, SI } }, + +{ "macchw", XO(4,172,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchw.", XO(4,172,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwo", XO(4,172,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwo.", XO(4,172,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchws", XO(4,236,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchws.", XO(4,236,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwso", XO(4,236,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwso.", XO(4,236,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsu", XO(4,204,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsu.", XO(4,204,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsuo", XO(4,204,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwsuo.", XO(4,204,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwu", XO(4,140,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwu.", XO(4,140,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwuo", XO(4,140,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "macchwuo.", XO(4,140,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhw", XO(4,44,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhw.", XO(4,44,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwo", XO(4,44,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwo.", XO(4,44,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhws", XO(4,108,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhws.", XO(4,108,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwso", XO(4,108,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwso.", XO(4,108,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsu", XO(4,76,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsu.", XO(4,76,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsuo", XO(4,76,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwsuo.", XO(4,76,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwu", XO(4,12,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwu.", XO(4,12,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwuo", XO(4,12,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "machhwuo.", XO(4,12,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhw", XO(4,428,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhw.", XO(4,428,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwo", XO(4,428,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwo.", XO(4,428,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhws", XO(4,492,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhws.", XO(4,492,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwso", XO(4,492,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwso.", XO(4,492,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsu", XO(4,460,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsu.", XO(4,460,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsuo", XO(4,460,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwsuo.", XO(4,460,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwu", XO(4,396,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwu.", XO(4,396,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwuo", XO(4,396,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "maclhwuo.", XO(4,396,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchw", XRC(4,168,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchw.", XRC(4,168,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchwu", XRC(4,136,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulchwu.", XRC(4,136,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhw", XRC(4,40,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhw.", XRC(4,40,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhwu", XRC(4,8,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mulhhwu.", XRC(4,8,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhw", XRC(4,424,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhw.", XRC(4,424,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhwu", XRC(4,392,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mullhwu.", XRC(4,392,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchw", XO(4,174,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchw.", XO(4,174,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwo", XO(4,174,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwo.", XO(4,174,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchws", XO(4,238,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchws.", XO(4,238,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwso", XO(4,238,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmacchwso.", XO(4,238,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhw", XO(4,46,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhw.", XO(4,46,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwo", XO(4,46,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwo.", XO(4,46,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhws", XO(4,110,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhws.", XO(4,110,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwso", XO(4,110,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmachhwso.", XO(4,110,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhw", XO(4,430,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhw.", XO(4,430,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwo", XO(4,430,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwo.", XO(4,430,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhws", XO(4,494,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhws.", XO(4,494,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwso", XO(4,494,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "nmaclhwso.", XO(4,494,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, +{ "mfvscr", VX(4, 1540), VX_MASK, PPCVEC, { VD } }, +{ "mtvscr", VX(4, 1604), VX_MASK, PPCVEC, { VB } }, + + /* Double-precision opcodes. */ + /* Some of these conflict with AltiVec, so move them before, since + PPCVEC includes the PPC_OPCODE_PPC set. */ +{ "efscfd", VX(4, 719), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdabs", VX(4, 740), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdnabs", VX(4, 741), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdneg", VX(4, 742), VX_MASK, PPCEFS, { RS, RA } }, +{ "efdadd", VX(4, 736), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdsub", VX(4, 737), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdmul", VX(4, 744), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efddiv", VX(4, 745), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efdcmpgt", VX(4, 748), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcmplt", VX(4, 749), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcmpeq", VX(4, 750), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtstgt", VX(4, 764), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtstlt", VX(4, 765), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdtsteq", VX(4, 766), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efdcfsi", VX(4, 753), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfsid", VX(4, 739), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfui", VX(4, 752), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfuid", VX(4, 738), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfsf", VX(4, 755), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfuf", VX(4, 754), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsi", VX(4, 757), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsidz",VX(4, 747), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsiz", VX(4, 762), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctui", VX(4, 756), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuidz",VX(4, 746), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuiz", VX(4, 760), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctsf", VX(4, 759), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdctuf", VX(4, 758), VX_MASK, PPCEFS, { RS, RB } }, +{ "efdcfs", VX(4, 751), VX_MASK, PPCEFS, { RS, RB } }, + /* End of double-precision opcodes. */ + +{ "vaddcuw", VX(4, 384), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddfp", VX(4, 10), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddsbs", VX(4, 768), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddshs", VX(4, 832), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddsws", VX(4, 896), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddubm", VX(4, 0), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vaddubs", VX(4, 512), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduhm", VX(4, 64), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduhs", VX(4, 576), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduwm", VX(4, 128), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vadduws", VX(4, 640), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vand", VX(4, 1028), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vandc", VX(4, 1092), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsb", VX(4, 1282), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsh", VX(4, 1346), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgsw", VX(4, 1410), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavgub", VX(4, 1026), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavguh", VX(4, 1090), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vavguw", VX(4, 1154), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcfsx", VX(4, 842), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vcfux", VX(4, 778), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vcmpbfp", VXR(4, 966, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpbfp.", VXR(4, 966, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpeqfp", VXR(4, 198, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequb", VXR(4, 6, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequb.", VXR(4, 6, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequh", VXR(4, 70, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequh.", VXR(4, 70, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequw", VXR(4, 134, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgefp", VXR(4, 454, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtfp", VXR(4, 710, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsb", VXR(4, 774, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsh", VXR(4, 838, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsw", VXR(4, 902, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtub", VXR(4, 518, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuh", VXR(4, 582, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuw", VXR(4, 646, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, +{ "vctsxs", VX(4, 970), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vctuxs", VX(4, 906), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vexptefp", VX(4, 394), VX_MASK, PPCVEC, { VD, VB } }, +{ "vlogefp", VX(4, 458), VX_MASK, PPCVEC, { VD, VB } }, +{ "vmaddfp", VXA(4, 46), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, +{ "vmaxfp", VX(4, 1034), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsb", VX(4, 258), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsh", VX(4, 322), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxsw", VX(4, 386), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxub", VX(4, 2), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxuh", VX(4, 66), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmaxuw", VX(4, 130), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmhaddshs", VXA(4, 32), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmhraddshs", VXA(4, 33), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vminfp", VX(4, 1098), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsb", VX(4, 770), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsh", VX(4, 834), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminsw", VX(4, 898), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminub", VX(4, 514), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminuh", VX(4, 578), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vminuw", VX(4, 642), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmladduhm", VXA(4, 34), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmrghb", VX(4, 12), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrghh", VX(4, 76), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrghw", VX(4, 140), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglb", VX(4, 268), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglh", VX(4, 332), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmrglw", VX(4, 396), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmsummbm", VXA(4, 37), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumshm", VXA(4, 40), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumshs", VXA(4, 41), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumubm", VXA(4, 36), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumuhm", VXA(4, 38), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmsumuhs", VXA(4, 39), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vmulesb", VX(4, 776), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulesh", VX(4, 840), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuleub", VX(4, 520), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuleuh", VX(4, 584), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulosb", VX(4, 264), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulosh", VX(4, 328), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmuloub", VX(4, 8), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vmulouh", VX(4, 72), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vnmsubfp", VXA(4, 47), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, +{ "vnor", VX(4, 1284), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vor", VX(4, 1156), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vperm", VXA(4, 43), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vpkpx", VX(4, 782), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkshss", VX(4, 398), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkshus", VX(4, 270), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkswss", VX(4, 462), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkswus", VX(4, 334), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuhum", VX(4, 14), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuhus", VX(4, 142), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuwum", VX(4, 78), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vpkuwus", VX(4, 206), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrefp", VX(4, 266), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfim", VX(4, 714), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfin", VX(4, 522), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfip", VX(4, 650), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrfiz", VX(4, 586), VX_MASK, PPCVEC, { VD, VB } }, +{ "vrlb", VX(4, 4), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrlw", VX(4, 132), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vrsqrtefp", VX(4, 330), VX_MASK, PPCVEC, { VD, VB } }, +{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, +{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslb", VX(4, 260), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsldoi", VXA(4, 44), VXA_MASK, PPCVEC, { VD, VA, VB, SHB } }, +{ "vslh", VX(4, 324), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslo", VX(4, 1036), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vslw", VX(4, 388), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vspltb", VX(4, 524), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vsplth", VX(4, 588), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vspltisb", VX(4, 780), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltish", VX(4, 844), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltisw", VX(4, 908), VX_MASK, PPCVEC, { VD, SIMM } }, +{ "vspltw", VX(4, 652), VX_MASK, PPCVEC, { VD, VB, UIMM } }, +{ "vsr", VX(4, 708), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrab", VX(4, 772), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrah", VX(4, 836), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsraw", VX(4, 900), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrb", VX(4, 516), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrh", VX(4, 580), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsro", VX(4, 1100), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsrw", VX(4, 644), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubcuw", VX(4, 1408), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubfp", VX(4, 74), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubsbs", VX(4, 1792), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubshs", VX(4, 1856), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubsws", VX(4, 1920), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsububm", VX(4, 1024), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsububs", VX(4, 1536), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuhm", VX(4, 1088), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuhs", VX(4, 1600), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuwm", VX(4, 1152), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsubuws", VX(4, 1664), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsumsws", VX(4, 1928), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum2sws", VX(4, 1672), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4sbs", VX(4, 1800), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4shs", VX(4, 1608), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vsum4ubs", VX(4, 1544), VX_MASK, PPCVEC, { VD, VA, VB } }, +{ "vupkhpx", VX(4, 846), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupkhsb", VX(4, 526), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupkhsh", VX(4, 590), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklpx", VX(4, 974), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklsb", VX(4, 654), VX_MASK, PPCVEC, { VD, VB } }, +{ "vupklsh", VX(4, 718), VX_MASK, PPCVEC, { VD, VB } }, +{ "vxor", VX(4, 1220), VX_MASK, PPCVEC, { VD, VA, VB } }, + +{ "evaddw", VX(4, 512), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evaddiw", VX(4, 514), VX_MASK, PPCSPE, { RS, RB, UIMM } }, +{ "evsubfw", VX(4, 516), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsubw", VX(4, 516), VX_MASK, PPCSPE, { RS, RB, RA } }, +{ "evsubifw", VX(4, 518), VX_MASK, PPCSPE, { RS, UIMM, RB } }, +{ "evsubiw", VX(4, 518), VX_MASK, PPCSPE, { RS, RB, UIMM } }, +{ "evabs", VX(4, 520), VX_MASK, PPCSPE, { RS, RA } }, +{ "evneg", VX(4, 521), VX_MASK, PPCSPE, { RS, RA } }, +{ "evextsb", VX(4, 522), VX_MASK, PPCSPE, { RS, RA } }, +{ "evextsh", VX(4, 523), VX_MASK, PPCSPE, { RS, RA } }, +{ "evrndw", VX(4, 524), VX_MASK, PPCSPE, { RS, RA } }, +{ "evcntlzw", VX(4, 525), VX_MASK, PPCSPE, { RS, RA } }, +{ "evcntlsw", VX(4, 526), VX_MASK, PPCSPE, { RS, RA } }, + +{ "brinc", VX(4, 527), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evand", VX(4, 529), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evandc", VX(4, 530), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmr", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, BBA } }, +{ "evor", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evorc", VX(4, 539), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evxor", VX(4, 534), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "eveqv", VX(4, 537), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evnand", VX(4, 542), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evnot", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, BBA } }, +{ "evnor", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evrlw", VX(4, 552), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evrlwi", VX(4, 554), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evslw", VX(4, 548), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evslwi", VX(4, 550), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsrws", VX(4, 545), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsrwu", VX(4, 544), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evsrwis", VX(4, 547), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsrwiu", VX(4, 546), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, +{ "evsplati", VX(4, 553), VX_MASK, PPCSPE, { RS, SIMM } }, +{ "evsplatfi", VX(4, 555), VX_MASK, PPCSPE, { RS, SIMM } }, +{ "evmergehi", VX(4, 556), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergelo", VX(4, 557), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergehilo",VX(4,558), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmergelohi",VX(4,559), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evcmpgts", VX(4, 561), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpgtu", VX(4, 560), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmplts", VX(4, 563), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpltu", VX(4, 562), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evcmpeq", VX(4, 564), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evsel", EVSEL(4,79),EVSEL_MASK, PPCSPE, { RS, RA, RB, CRFS } }, + +{ "evldd", VX(4, 769), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evlddx", VX(4, 768), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evldw", VX(4, 771), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evldwx", VX(4, 770), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evldh", VX(4, 773), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evldhx", VX(4, 772), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhe", VX(4, 785), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhex", VX(4, 784), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhou", VX(4, 789), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhoux", VX(4, 788), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhos", VX(4, 791), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhosx", VX(4, 790), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwwsplat",VX(4, 793), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwwsplatx",VX(4, 792), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlwhsplat",VX(4, 797), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evlwhsplatx",VX(4, 796), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhesplat",VX(4, 777), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhesplatx",VX(4, 776), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhousplat",VX(4, 781), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhousplatx",VX(4, 780), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evlhhossplat",VX(4, 783), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, +{ "evlhhossplatx",VX(4, 782), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evstdd", VX(4, 801), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstddx", VX(4, 800), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstdw", VX(4, 803), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstdwx", VX(4, 802), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstdh", VX(4, 805), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, +{ "evstdhx", VX(4, 804), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwwe", VX(4, 825), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwwex", VX(4, 824), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwwo", VX(4, 829), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwwox", VX(4, 828), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwhe", VX(4, 817), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwhex", VX(4, 816), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evstwho", VX(4, 821), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, +{ "evstwhox", VX(4, 820), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evfsabs", VX(4, 644), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsnabs", VX(4, 645), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsneg", VX(4, 646), VX_MASK, PPCSPE, { RS, RA } }, +{ "evfsadd", VX(4, 640), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfssub", VX(4, 641), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfsmul", VX(4, 648), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfsdiv", VX(4, 649), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evfscmpgt", VX(4, 652), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscmplt", VX(4, 653), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscmpeq", VX(4, 654), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststgt", VX(4, 668), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststlt", VX(4, 669), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfststeq", VX(4, 670), VX_MASK, PPCSPE, { CRFD, RA, RB } }, +{ "evfscfui", VX(4, 656), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctuiz", VX(4, 664), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfsi", VX(4, 657), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfuf", VX(4, 658), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfscfsf", VX(4, 659), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctui", VX(4, 660), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsi", VX(4, 661), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsiz", VX(4, 666), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctuf", VX(4, 662), VX_MASK, PPCSPE, { RS, RB } }, +{ "evfsctsf", VX(4, 663), VX_MASK, PPCSPE, { RS, RB } }, + +{ "efsabs", VX(4, 708), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsnabs", VX(4, 709), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsneg", VX(4, 710), VX_MASK, PPCEFS, { RS, RA } }, +{ "efsadd", VX(4, 704), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efssub", VX(4, 705), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efsmul", VX(4, 712), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efsdiv", VX(4, 713), VX_MASK, PPCEFS, { RS, RA, RB } }, +{ "efscmpgt", VX(4, 716), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscmplt", VX(4, 717), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscmpeq", VX(4, 718), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststgt", VX(4, 732), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststlt", VX(4, 733), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efststeq", VX(4, 734), VX_MASK, PPCEFS, { CRFD, RA, RB } }, +{ "efscfui", VX(4, 720), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctuiz", VX(4, 728), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfsi", VX(4, 721), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfuf", VX(4, 722), VX_MASK, PPCEFS, { RS, RB } }, +{ "efscfsf", VX(4, 723), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctui", VX(4, 724), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsi", VX(4, 725), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsiz", VX(4, 730), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctuf", VX(4, 726), VX_MASK, PPCEFS, { RS, RB } }, +{ "efsctsf", VX(4, 727), VX_MASK, PPCEFS, { RS, RB } }, + +{ "evmhossf", VX(4, 1031), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossfa", VX(4, 1063), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmf", VX(4, 1039), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfa", VX(4, 1071), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmi", VX(4, 1037), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmia", VX(4, 1069), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumi", VX(4, 1036), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumia", VX(4, 1068), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessf", VX(4, 1027), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfa", VX(4, 1059), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmf", VX(4, 1035), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfa", VX(4, 1067), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmi", VX(4, 1033), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmia", VX(4, 1065), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumi", VX(4, 1032), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumia", VX(4, 1064), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhossfaaw",VX(4, 1287), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossiaaw",VX(4, 1285), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfaaw",VX(4, 1295), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmiaaw",VX(4, 1293), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhousiaaw",VX(4, 1284), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumiaaw",VX(4, 1292), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfaaw",VX(4, 1283), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessiaaw",VX(4, 1281), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfaaw",VX(4, 1291), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmiaaw",VX(4, 1289), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheusiaaw",VX(4, 1280), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumiaaw",VX(4, 1288), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhossfanw",VX(4, 1415), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhossianw",VX(4, 1413), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmfanw",VX(4, 1423), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhosmianw",VX(4, 1421), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhousianw",VX(4, 1412), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhoumianw",VX(4, 1420), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessfanw",VX(4, 1411), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhessianw",VX(4, 1409), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmfanw",VX(4, 1419), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhesmianw",VX(4, 1417), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheusianw",VX(4, 1408), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmheumianw",VX(4, 1416), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhogsmfaa",VX(4, 1327), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogsmiaa",VX(4, 1325), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogumiaa",VX(4, 1324), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmfaa",VX(4, 1323), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmiaa",VX(4, 1321), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegumiaa",VX(4, 1320), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmhogsmfan",VX(4, 1455), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogsmian",VX(4, 1453), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhogumian",VX(4, 1452), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmfan",VX(4, 1451), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegsmian",VX(4, 1449), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmhegumian",VX(4, 1448), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwhssf", VX(4, 1095), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhssfa", VX(4, 1127), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmf", VX(4, 1103), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmfa", VX(4, 1135), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmi", VX(4, 1101), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhsmia", VX(4, 1133), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhumi", VX(4, 1100), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwhumia", VX(4, 1132), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlumi", VX(4, 1096), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumia", VX(4, 1128), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlssiaaw",VX(4, 1345), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlsmiaaw",VX(4, 1353), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlusiaaw",VX(4, 1344), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumiaaw",VX(4, 1352), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwlssianw",VX(4, 1473), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlsmianw",VX(4, 1481), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlusianw",VX(4, 1472), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwlumianw",VX(4, 1480), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssf", VX(4, 1107), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwssfa", VX(4, 1139), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmf", VX(4, 1115), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfa", VX(4, 1147), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmi", VX(4, 1113), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmia", VX(4, 1145), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumi", VX(4, 1112), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumia", VX(4, 1144), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssfaa", VX(4, 1363), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfaa", VX(4, 1371), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmiaa", VX(4, 1369), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumiaa", VX(4, 1368), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evmwssfan", VX(4, 1491), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmfan", VX(4, 1499), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwsmian", VX(4, 1497), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evmwumian", VX(4, 1496), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "evaddssiaaw",VX(4, 1217), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddsmiaaw",VX(4, 1225), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddusiaaw",VX(4, 1216), VX_MASK, PPCSPE, { RS, RA } }, +{ "evaddumiaaw",VX(4, 1224), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evsubfssiaaw",VX(4, 1219), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfsmiaaw",VX(4, 1227), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfusiaaw",VX(4, 1218), VX_MASK, PPCSPE, { RS, RA } }, +{ "evsubfumiaaw",VX(4, 1226), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evmra", VX(4, 1220), VX_MASK, PPCSPE, { RS, RA } }, + +{ "evdivws", VX(4, 1222), VX_MASK, PPCSPE, { RS, RA, RB } }, +{ "evdivwu", VX(4, 1223), VX_MASK, PPCSPE, { RS, RA, RB } }, + +{ "mulli", OP(7), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "muli", OP(7), OP_MASK, PWRCOM, { RT, RA, SI } }, + +{ "subfic", OP(8), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "sfi", OP(8), OP_MASK, PWRCOM, { RT, RA, SI } }, + +{ "dozi", OP(9), OP_MASK, M601, { RT, RA, SI } }, + +{ "bce", B(9,0,0), B_MASK, BOOKE64, { BO, BI, BD } }, +{ "bcel", B(9,0,1), B_MASK, BOOKE64, { BO, BI, BD } }, +{ "bcea", B(9,1,0), B_MASK, BOOKE64, { BO, BI, BDA } }, +{ "bcela", B(9,1,1), B_MASK, BOOKE64, { BO, BI, BDA } }, + +{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } }, +{ "cmpldi", OPL(10,1), OPL_MASK, PPC64, { OBF, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PWRCOM, { BF, RA, UI } }, + +{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } }, +{ "cmpdi", OPL(11,1), OPL_MASK, PPC64, { OBF, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PWRCOM, { BF, RA, SI } }, + +{ "addic", OP(12), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "ai", OP(12), OP_MASK, PWRCOM, { RT, RA, SI } }, +{ "subic", OP(12), OP_MASK, PPCCOM, { RT, RA, NSI } }, + +{ "addic.", OP(13), OP_MASK, PPCCOM, { RT, RA, SI } }, +{ "ai.", OP(13), OP_MASK, PWRCOM, { RT, RA, SI } }, +{ "subic.", OP(13), OP_MASK, PPCCOM, { RT, RA, NSI } }, + +{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } }, +{ "lil", OP(14), DRA_MASK, PWRCOM, { RT, SI } }, +{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } }, +{ "cal", OP(14), OP_MASK, PWRCOM, { RT, D, RA0 } }, +{ "subi", OP(14), OP_MASK, PPCCOM, { RT, RA0, NSI } }, +{ "la", OP(14), OP_MASK, PPCCOM, { RT, D, RA0 } }, + +{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SISIGNOPT } }, +{ "liu", OP(15), DRA_MASK, PWRCOM, { RT, SISIGNOPT } }, +{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SISIGNOPT } }, +{ "cau", OP(15), OP_MASK, PWRCOM, { RT,RA0,SISIGNOPT } }, +{ "subis", OP(15), OP_MASK, PPCCOM, { RT, RA0, NSI } }, + +{ "bdnz-", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdnz+", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdnz", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BD } }, +{ "bdn", BBO(16,BODNZ,0,0), BBOATBI_MASK, PWRCOM, { BD } }, +{ "bdnzl-", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdnzl+", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdnzl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BD } }, +{ "bdnl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PWRCOM, { BD } }, +{ "bdnza-", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdnza+", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdnza", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDA } }, +{ "bdna", BBO(16,BODNZ,1,0), BBOATBI_MASK, PWRCOM, { BDA } }, +{ "bdnzla-", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdnzla+", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdnzla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDA } }, +{ "bdnla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PWRCOM, { BDA } }, +{ "bdz-", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdz+", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdz", BBO(16,BODZ,0,0), BBOATBI_MASK, COM, { BD } }, +{ "bdzl-", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, +{ "bdzl+", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, +{ "bdzl", BBO(16,BODZ,0,1), BBOATBI_MASK, COM, { BD } }, +{ "bdza-", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdza+", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdza", BBO(16,BODZ,1,0), BBOATBI_MASK, COM, { BDA } }, +{ "bdzla-", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, +{ "bdzla+", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, +{ "bdzla", BBO(16,BODZ,1,1), BBOATBI_MASK, COM, { BDA } }, +{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, +{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, +{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, +{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, +{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, +{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, +{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, +{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, +{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bt-", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bt+", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bt", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbt", BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "btl-", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "btl+", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "btl", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbtl", BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bta-", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bta+", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bta", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbta", BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "btla-", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "btla+", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "btla", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbtla", BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bf-", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bf+", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bf", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbf", BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bfl-", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, +{ "bfl+", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, +{ "bfl", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, +{ "bbfl", BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, +{ "bfa-", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bfa+", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bfa", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbfa", BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bfla-", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, +{ "bfla+", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, +{ "bfla", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, +{ "bbfla", BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, +{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, +{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, +{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, +{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, +{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, +{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, +{ "bc-", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDM } }, +{ "bc+", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDP } }, +{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } }, +{ "bcl-", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDM } }, +{ "bcl+", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDP } }, +{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } }, +{ "bca-", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDMA } }, +{ "bca+", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDPA } }, +{ "bca", B(16,1,0), B_MASK, COM, { BO, BI, BDA } }, +{ "bcla-", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDMA } }, +{ "bcla+", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDPA } }, +{ "bcla", B(16,1,1), B_MASK, COM, { BO, BI, BDA } }, + +{ "sc", SC(17,1,0), SC_MASK, PPC, { LEV } }, +{ "svc", SC(17,0,0), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, +{ "svcl", SC(17,0,1), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, +{ "svca", SC(17,1,0), SC_MASK, PWRCOM, { SV } }, +{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, + +{ "b", B(18,0,0), B_MASK, COM, { LI } }, +{ "bl", B(18,0,1), B_MASK, COM, { LI } }, +{ "ba", B(18,1,0), B_MASK, COM, { LIA } }, +{ "bla", B(18,1,1), B_MASK, COM, { LIA } }, + +{ "mcrf", XL(19,0), XLBB_MASK|(3 << 21)|(3 << 16), COM, { BF, BFA } }, + +{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM, { 0 } }, +{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM, { 0 } }, +{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlr-", XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlr+", XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, +{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, +{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlr-", XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlr+", XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlr-", XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlr-", XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlr+", XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelr-", XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelr+", XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, +{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlr-", XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlr+", XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM, { BI } }, +{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlrl-", XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btlrl+", XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflr-", XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflr+", XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflrl-", XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bflrl+", XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM, { BI } }, +{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bclr", XLLK(19,16,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bclrl", XLLK(19,16,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcr", XLLK(19,16,0), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bcrl", XLLK(19,16,1), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bclre", XLLK(19,17,0), XLBB_MASK, BOOKE64, { BO, BI } }, +{ "bclrel", XLLK(19,17,1), XLBB_MASK, BOOKE64, { BO, BI } }, + +{ "rfid", XL(19,18), 0xffffffff, PPC64, { 0 } }, + +{ "crnot", XL(19,33), XL_MASK, PPCCOM, { BT, BA, BBA } }, +{ "crnor", XL(19,33), XL_MASK, COM, { BT, BA, BB } }, +{ "rfmci", X(19,38), 0xffffffff, PPCRFMCI, { 0 } }, + +{ "rfi", XL(19,50), 0xffffffff, COM, { 0 } }, +{ "rfci", XL(19,51), 0xffffffff, PPC403 | BOOKE, { 0 } }, + +{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, + +{ "crandc", XL(19,129), XL_MASK, COM, { BT, BA, BB } }, + +{ "isync", XL(19,150), 0xffffffff, PPCCOM, { 0 } }, +{ "ics", XL(19,150), 0xffffffff, PWRCOM, { 0 } }, + +{ "crclr", XL(19,193), XL_MASK, PPCCOM, { BT, BAT, BBA } }, +{ "crxor", XL(19,193), XL_MASK, COM, { BT, BA, BB } }, + +{ "crnand", XL(19,225), XL_MASK, COM, { BT, BA, BB } }, + +{ "crand", XL(19,257), XL_MASK, COM, { BT, BA, BB } }, + +{ "hrfid", XL(19,274), 0xffffffff, POWER5 | CELL, { 0 } }, + +{ "crset", XL(19,289), XL_MASK, PPCCOM, { BT, BAT, BBA } }, +{ "creqv", XL(19,289), XL_MASK, COM, { BT, BA, BB } }, + +{ "doze", XL(19,402), 0xffffffff, POWER6, { 0 } }, + +{ "crorc", XL(19,417), XL_MASK, COM, { BT, BA, BB } }, + +{ "nap", XL(19,434), 0xffffffff, POWER6, { 0 } }, + +{ "crmove", XL(19,449), XL_MASK, PPCCOM, { BT, BA, BBA } }, +{ "cror", XL(19,449), XL_MASK, COM, { BT, BA, BB } }, + +{ "sleep", XL(19,466), 0xffffffff, POWER6, { 0 } }, +{ "rvwinkle", XL(19,498), 0xffffffff, POWER6, { 0 } }, + +{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } }, +{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } }, +{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, +{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, +{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctr-", XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctr+", XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctr-", XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctr+", XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPCCOM, { BI } }, +{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, +{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } }, +{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, +{ "bcctr", XLLK(19,528,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcctrl", XLLK(19,528,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, +{ "bcc", XLLK(19,528,0), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bccl", XLLK(19,528,1), XLBB_MASK, PWRCOM, { BO, BI } }, +{ "bcctre", XLLK(19,529,0), XLBB_MASK, BOOKE64, { BO, BI } }, +{ "bcctrel", XLLK(19,529,1), XLBB_MASK, BOOKE64, { BO, BI } }, + +{ "rlwimi", M(20,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlimi", M(20,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rlwimi.", M(20,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlimi.", M(20,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rotlwi", MME(21,31,0), MMBME_MASK, PPCCOM, { RA, RS, SH } }, +{ "clrlwi", MME(21,31,0), MSHME_MASK, PPCCOM, { RA, RS, MB } }, +{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlinm", M(21,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, +{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPCCOM, { RA,RS,SH } }, +{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPCCOM, { RA, RS, MB } }, +{ "rlwinm.", M(21,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, +{ "rlinm.", M(21,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, + +{ "rlmi", M(22,0), M_MASK, M601, { RA,RS,RB,MBE,ME } }, +{ "rlmi.", M(22,1), M_MASK, M601, { RA,RS,RB,MBE,ME } }, + +{ "be", B(22,0,0), B_MASK, BOOKE64, { LI } }, +{ "bel", B(22,0,1), B_MASK, BOOKE64, { LI } }, +{ "bea", B(22,1,0), B_MASK, BOOKE64, { LIA } }, +{ "bela", B(22,1,1), B_MASK, BOOKE64, { LIA } }, + +{ "rotlw", MME(23,31,0), MMBME_MASK, PPCCOM, { RA, RS, RB } }, +{ "rlwnm", M(23,0), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, +{ "rlnm", M(23,0), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, +{ "rotlw.", MME(23,31,1), MMBME_MASK, PPCCOM, { RA, RS, RB } }, +{ "rlwnm.", M(23,1), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, +{ "rlnm.", M(23,1), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, + +{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } }, +{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "oril", OP(24), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "oris", OP(25), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "oriu", OP(25), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "xori", OP(26), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "xoril", OP(26), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "xoriu", OP(27), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "andi.", OP(28), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "andil.", OP(28), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "andis.", OP(29), OP_MASK, PPCCOM, { RA, RS, UI } }, +{ "andiu.", OP(29), OP_MASK, PWRCOM, { RA, RS, UI } }, + +{ "rotldi", MD(30,0,0), MDMB_MASK, PPC64, { RA, RS, SH6 } }, +{ "clrldi", MD(30,0,0), MDSH_MASK, PPC64, { RA, RS, MB6 } }, +{ "rldicl", MD(30,0,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC64, { RA, RS, SH6 } }, +{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC64, { RA, RS, MB6 } }, +{ "rldicl.", MD(30,0,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rldicr", MD(30,1,0), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, +{ "rldicr.", MD(30,1,1), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, + +{ "rldic", MD(30,2,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rldic.", MD(30,2,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rldimi", MD(30,3,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, +{ "rldimi.", MD(30,3,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, + +{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC64, { RA, RS, RB } }, +{ "rldcl", MDS(30,8,0), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, +{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC64, { RA, RS, RB } }, +{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, + +{ "rldcr", MDS(30,9,0), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, +{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, + +{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, +{ "cmpd", XOPL(31,0,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, +{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmp", X(31,0), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, + +{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tllt", XTO(31,4,TOLLT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPCCOM, { RA, RB } }, +{ "teq", XTO(31,4,TOEQ), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlge", XTO(31,4,TOLGE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlle", XTO(31,4,TOLLE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlng", XTO(31,4,TOLNG), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tgt", XTO(31,4,TOGT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twge", XTO(31,4,TOGE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tge", XTO(31,4,TOGE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twnl", XTO(31,4,TONL), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tnl", XTO(31,4,TONL), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tlt", XTO(31,4,TOLT), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twle", XTO(31,4,TOLE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tle", XTO(31,4,TOLE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twng", XTO(31,4,TONG), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tng", XTO(31,4,TONG), XTO_MASK, PWRCOM, { RA, RB } }, +{ "twne", XTO(31,4,TONE), XTO_MASK, PPCCOM, { RA, RB } }, +{ "tne", XTO(31,4,TONE), XTO_MASK, PWRCOM, { RA, RB } }, +{ "trap", XTO(31,4,TOU), 0xffffffff, PPCCOM, { 0 } }, +{ "tw", X(31,4), X_MASK, PPCCOM, { TO, RA, RB } }, +{ "t", X(31,4), X_MASK, PWRCOM, { TO, RA, RB } }, + +{ "subfc", XO(31,8,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sf", XO(31,8,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sf.", XO(31,8,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RB, RA } }, +{ "subfco", XO(31,8,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfo", XO(31,8,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco.", XO(31,8,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfo.", XO(31,8,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addc", XO(31,10,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "a", XO(31,10,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addc.", XO(31,10,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "a.", XO(31,10,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addco", XO(31,10,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ao", XO(31,10,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addco.", XO(31,10,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ao.", XO(31,10,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "isellt", X(31,15), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "iselgt", X(31,47), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "iseleq", X(31,79), X_MASK, PPCISEL, { RT, RA, RB } }, +{ "isel", XISEL(31,15), XISEL_MASK, PPCISEL, { RT, RA, RB, CRB } }, + +{ "mfocrf", XFXM(31,19,0,1), XFXFXM_MASK, COM, { RT, FXM } }, +{ "mfcr", X(31,19), XRARB_MASK, NOPOWER4 | COM, { RT } }, +{ "mfcr", X(31,19), XFXFXM_MASK, POWER4, { RT, FXM4 } }, + +{ "lwarx", X(31,20), XEH_MASK, PPC, { RT, RA0, RB, EH } }, + +{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } }, + +{ "icbt", X(31,22), X_MASK, BOOKE|PPCE300, { CT, RA, RB } }, +{ "icbt", X(31,262), XRT_MASK, PPC403, { RA, RB } }, + +{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lx", X(31,23), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sl", XRC(31,24,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "slw.", XRC(31,24,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sl.", XRC(31,24,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "cntlzw", XRC(31,26,0), XRB_MASK, PPCCOM, { RA, RS } }, +{ "cntlz", XRC(31,26,0), XRB_MASK, PWRCOM, { RA, RS } }, +{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPCCOM, { RA, RS } }, +{ "cntlz.", XRC(31,26,1), XRB_MASK, PWRCOM, { RA, RS } }, + +{ "sld", XRC(31,27,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "sld.", XRC(31,27,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } }, +{ "and.", XRC(31,28,1), X_MASK, COM, { RA, RS, RB } }, + +{ "maskg", XRC(31,29,0), X_MASK, M601, { RA, RS, RB } }, +{ "maskg.", XRC(31,29,1), X_MASK, M601, { RA, RS, RB } }, + +{ "icbte", X(31,30), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "lwzxe", X(31,31), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, +{ "cmpld", XOPL(31,32,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, +{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmpl", X(31,32), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, + +{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "ldux", X(31,53), X_MASK, PPC64, { RT, RAL, RB } }, + +{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, + +{ "lwzux", X(31,55), X_MASK, PPCCOM, { RT, RAL, RB } }, +{ "lux", X(31,55), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dcbste", X(31,62), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lwzuxe", X(31,63), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC64, { RA, RS } }, +{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC64, { RA, RS } }, + +{ "andc", XRC(31,60,0), X_MASK, COM, { RA, RS, RB } }, +{ "andc.", XRC(31,60,1), X_MASK, COM, { RA, RS, RB } }, + +{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC64, { RA, RB } }, +{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC64, { RA, RB } }, +{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC64, { RA, RB } }, +{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC64, { RA, RB } }, +{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC64, { RA, RB } }, +{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC64, { RA, RB } }, +{ "td", X(31,68), X_MASK, PPC64, { TO, RA, RB } }, + +{ "mulhd", XO(31,73,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "dlmzb", XRC(31,78,0), X_MASK, PPC403|PPC440, { RA, RS, RB } }, +{ "dlmzb.", XRC(31,78,1), X_MASK, PPC403|PPC440, { RA, RS, RB } }, + +{ "mtsrd", X(31,82), XRB_MASK|(1<<20), PPC64, { SR, RS } }, + +{ "mfmsr", X(31,83), XRARB_MASK, COM, { RT } }, + +{ "ldarx", X(31,84), XEH_MASK, PPC64, { RT, RA0, RB, EH } }, + +{ "dcbfl", XOPL(31,86,1), XRT_MASK, POWER5, { RA, RB } }, +{ "dcbf", X(31,86), XLRT_MASK, PPC, { RA, RB, L } }, + +{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } }, + +{ "dcbfe", X(31,94), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lbzxe", X(31,95), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } }, +{ "neg.", XO(31,104,0,1), XORB_MASK, COM, { RT, RA } }, +{ "nego", XO(31,104,1,0), XORB_MASK, COM, { RT, RA } }, +{ "nego.", XO(31,104,1,1), XORB_MASK, COM, { RT, RA } }, + +{ "mul", XO(31,107,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "mul.", XO(31,107,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "mulo", XO(31,107,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "mulo.", XO(31,107,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "mtsrdin", X(31,114), XRA_MASK, PPC64, { RS, RB } }, + +{ "clf", X(31,118), XTO_MASK, POWER, { RA, RB } }, + +{ "lbzux", X(31,119), X_MASK, COM, { RT, RAL, RB } }, + +{ "popcntb", X(31,122), XRB_MASK, POWER5, { RA, RS } }, + +{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } }, +{ "nor", XRC(31,124,0), X_MASK, COM, { RA, RS, RB } }, +{ "not.", XRC(31,124,1), X_MASK, COM, { RA, RS, RBS } }, +{ "nor.", XRC(31,124,1), X_MASK, COM, { RA, RS, RB } }, + +{ "lwarxe", X(31,126), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "lbzuxe", X(31,127), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "wrtee", X(31,131), XRARB_MASK, PPC403 | BOOKE, { RS } }, + +{ "dcbtstls",X(31,134), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfe", XO(31,136,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfe", XO(31,136,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfe.", XO(31,136,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfe.", XO(31,136,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfeo", XO(31,136,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfeo", XO(31,136,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "subfeo.", XO(31,136,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "sfeo.", XO(31,136,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "adde", XO(31,138,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ae", XO(31,138,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "adde.", XO(31,138,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "ae.", XO(31,138,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addeo", XO(31,138,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "aeo", XO(31,138,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addeo.", XO(31,138,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "aeo.", XO(31,138,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dcbtstlse",X(31,142),X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "mtocrf", XFXM(31,144,0,1), XFXFXM_MASK, COM, { FXM, RS } }, +{ "mtcr", XFXM(31,144,0xff,0), XRARB_MASK, COM, { RS }}, +{ "mtcrf", X(31,144), XFXFXM_MASK, COM, { FXM, RS } }, + +{ "mtmsr", X(31,146), XRARB_MASK, COM, { RS } }, + +{ "stdx", X(31,149), X_MASK, PPC64, { RS, RA0, RB } }, + +{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA0, RB } }, + +{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stx", X(31,151), X_MASK, PWRCOM, { RS, RA, RB } }, + +{ "stwcxe.", XRC(31,158,1), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stwxe", X(31,159), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "slq", XRC(31,152,0), X_MASK, M601, { RA, RS, RB } }, +{ "slq.", XRC(31,152,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sle", XRC(31,153,0), X_MASK, M601, { RA, RS, RB } }, +{ "sle.", XRC(31,153,1), X_MASK, M601, { RA, RS, RB } }, + +{ "prtyw", X(31,154), XRB_MASK, POWER6, { RA, RS } }, + +{ "wrteei", X(31,163), XE_MASK, PPC403 | BOOKE, { E } }, + +{ "dcbtls", X(31,166), X_MASK, PPCCHLK, { CT, RA, RB }}, +{ "dcbtlse", X(31,174), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "mtmsrd", X(31,178), XRLARB_MASK, PPC64, { RS, A_L } }, + +{ "stdux", X(31,181), X_MASK, PPC64, { RS, RAS, RB } }, + +{ "stwux", X(31,183), X_MASK, PPCCOM, { RS, RAS, RB } }, +{ "stux", X(31,183), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "sliq", XRC(31,184,0), X_MASK, M601, { RA, RS, SH } }, +{ "sliq.", XRC(31,184,1), X_MASK, M601, { RA, RS, SH } }, + +{ "prtyd", X(31,186), XRB_MASK, POWER6, { RA, RS } }, + +{ "stwuxe", X(31,191), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "subfze", XO(31,200,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfze", XO(31,200,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfze.", XO(31,200,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfzeo", XO(31,200,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfzeo.", XO(31,200,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "addze", XO(31,202,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "aze", XO(31,202,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addze.", XO(31,202,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "aze.", XO(31,202,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addzeo", XO(31,202,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "azeo", XO(31,202,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "azeo.", XO(31,202,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mtsr", X(31,210), XRB_MASK|(1<<20), COM32, { SR, RS } }, + +{ "stdcx.", XRC(31,214,1), X_MASK, PPC64, { RS, RA0, RB } }, + +{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } }, + +{ "sllq", XRC(31,216,0), X_MASK, M601, { RA, RS, RB } }, +{ "sllq.", XRC(31,216,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sleq", XRC(31,217,0), X_MASK, M601, { RA, RS, RB } }, +{ "sleq.", XRC(31,217,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stbxe", X(31,223), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "icblc", X(31,230), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfme", XO(31,232,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfme", XO(31,232,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfme.", XO(31,232,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfmeo", XO(31,232,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "sfmeo.", XO(31,232,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mulld", XO(31,233,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulld.", XO(31,233,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulldo", XO(31,233,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addme", XO(31,234,0,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ame", XO(31,234,0,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addme.", XO(31,234,0,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ame.", XO(31,234,0,1), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addmeo", XO(31,234,1,0), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ameo", XO(31,234,1,0), XORB_MASK, PWRCOM, { RT, RA } }, +{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } }, +{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } }, + +{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "muls.", XO(31,235,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullwo", XO(31,235,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "mulso", XO(31,235,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "mullwo.", XO(31,235,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "mulso.", XO(31,235,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "icblce", X(31,238), X_MASK, PPCCHLK64, { CT, RA, RB }}, +{ "mtsrin", X(31,242), XRA_MASK, PPC32, { RS, RB } }, +{ "mtsri", X(31,242), XRA_MASK, POWER32, { RS, RB } }, + +{ "dcbtst", X(31,246), X_MASK, PPC, { CT, RA, RB } }, + +{ "stbux", X(31,247), X_MASK, COM, { RS, RAS, RB } }, + +{ "slliq", XRC(31,248,0), X_MASK, M601, { RA, RS, SH } }, +{ "slliq.", XRC(31,248,1), X_MASK, M601, { RA, RS, SH } }, + +{ "dcbtste", X(31,253), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "stbuxe", X(31,255), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "mfdcrx", X(31,259), X_MASK, BOOKE, { RS, RA } }, + +{ "doz", XO(31,264,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "doz.", XO(31,264,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "dozo", XO(31,264,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "dozo.", XO(31,264,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "cax", XO(31,266,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "add.", XO(31,266,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "cax.", XO(31,266,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addo", XO(31,266,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "caxo", XO(31,266,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, +{ "addo.", XO(31,266,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, +{ "caxo.", XO(31,266,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, + +{ "tlbiel", X(31,274), XRTLRA_MASK, POWER4, { RB, L } }, + +{ "mfapidi", X(31,275), X_MASK, BOOKE, { RT, RA } }, + +{ "lscbx", XRC(31,277,0), X_MASK, M601, { RT, RA, RB } }, +{ "lscbx.", XRC(31,277,1), X_MASK, M601, { RT, RA, RB } }, + +{ "dcbt", X(31,278), X_MASK, PPC, { CT, RA, RB } }, + +{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } }, + +{ "eqv", XRC(31,284,0), X_MASK, COM, { RA, RS, RB } }, +{ "eqv.", XRC(31,284,1), X_MASK, COM, { RA, RS, RB } }, + +{ "dcbte", X(31,286), X_MASK, BOOKE64, { CT, RA, RB } }, + +{ "lhzxe", X(31,287), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "tlbie", X(31,306), XRTLRA_MASK, PPC, { RB, L } }, +{ "tlbi", X(31,306), XRT_MASK, POWER, { RA0, RB } }, + +{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, + +{ "lhzux", X(31,311), X_MASK, COM, { RT, RAL, RB } }, + +{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } }, +{ "xor.", XRC(31,316,1), X_MASK, COM, { RA, RS, RB } }, + +{ "lhzuxe", X(31,319), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "mfexisr", XSPR(31,323,64), XSPR_MASK, PPC403, { RT } }, +{ "mfexier", XSPR(31,323,66), XSPR_MASK, PPC403, { RT } }, +{ "mfbr0", XSPR(31,323,128), XSPR_MASK, PPC403, { RT } }, +{ "mfbr1", XSPR(31,323,129), XSPR_MASK, PPC403, { RT } }, +{ "mfbr2", XSPR(31,323,130), XSPR_MASK, PPC403, { RT } }, +{ "mfbr3", XSPR(31,323,131), XSPR_MASK, PPC403, { RT } }, +{ "mfbr4", XSPR(31,323,132), XSPR_MASK, PPC403, { RT } }, +{ "mfbr5", XSPR(31,323,133), XSPR_MASK, PPC403, { RT } }, +{ "mfbr6", XSPR(31,323,134), XSPR_MASK, PPC403, { RT } }, +{ "mfbr7", XSPR(31,323,135), XSPR_MASK, PPC403, { RT } }, +{ "mfbear", XSPR(31,323,144), XSPR_MASK, PPC403, { RT } }, +{ "mfbesr", XSPR(31,323,145), XSPR_MASK, PPC403, { RT } }, +{ "mfiocr", XSPR(31,323,160), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403, { RT } }, +{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403, { RT } }, +{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403, { RT } }, +{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403, { RT } }, +{ "mfdmasr", XSPR(31,323,224), XSPR_MASK, PPC403, { RT } }, +{ "mfdcr", X(31,323), X_MASK, PPC403 | BOOKE, { RT, SPR } }, + +{ "div", XO(31,331,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "div.", XO(31,331,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "divo", XO(31,331,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divo.", XO(31,331,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "mfpmr", X(31,334), X_MASK, PPCPMR, { RT, PMR }}, + +{ "mfmq", XSPR(31,339,0), XSPR_MASK, M601, { RT } }, +{ "mfxer", XSPR(31,339,1), XSPR_MASK, COM, { RT } }, +{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, COM, { RT } }, +{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, COM, { RT } }, +{ "mfdec", XSPR(31,339,6), XSPR_MASK, MFDEC1, { RT } }, +{ "mfdec", XSPR(31,339,22), XSPR_MASK, MFDEC2, { RT } }, +{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } }, +{ "mfctr", XSPR(31,339,9), XSPR_MASK, COM, { RT } }, +{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, +{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, COM, { RT } }, +{ "mfdar", XSPR(31,339,19), XSPR_MASK, COM, { RT } }, +{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, +{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, COM, { RT } }, +{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, COM, { RT } }, +{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, COM, { RT } }, +{ "mfcfar", XSPR(31,339,28), XSPR_MASK, POWER6, { RT } }, +{ "mfpid", XSPR(31,339,48), XSPR_MASK, BOOKE, { RT } }, +{ "mfpid", XSPR(31,339,945), XSPR_MASK, PPC403, { RT } }, +{ "mfcsrr0", XSPR(31,339,58), XSPR_MASK, BOOKE, { RT } }, +{ "mfcsrr1", XSPR(31,339,59), XSPR_MASK, BOOKE, { RT } }, +{ "mfdear", XSPR(31,339,61), XSPR_MASK, BOOKE, { RT } }, +{ "mfdear", XSPR(31,339,981), XSPR_MASK, PPC403, { RT } }, +{ "mfesr", XSPR(31,339,62), XSPR_MASK, BOOKE, { RT } }, +{ "mfesr", XSPR(31,339,980), XSPR_MASK, PPC403, { RT } }, +{ "mfivpr", XSPR(31,339,63), XSPR_MASK, BOOKE, { RT } }, +{ "mfcmpa", XSPR(31,339,144), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpb", XSPR(31,339,145), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpc", XSPR(31,339,146), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpd", XSPR(31,339,147), XSPR_MASK, PPC860, { RT } }, +{ "mficr", XSPR(31,339,148), XSPR_MASK, PPC860, { RT } }, +{ "mfder", XSPR(31,339,149), XSPR_MASK, PPC860, { RT } }, +{ "mfcounta", XSPR(31,339,150), XSPR_MASK, PPC860, { RT } }, +{ "mfcountb", XSPR(31,339,151), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpe", XSPR(31,339,152), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpf", XSPR(31,339,153), XSPR_MASK, PPC860, { RT } }, +{ "mfcmpg", XSPR(31,339,154), XSPR_MASK, PPC860, { RT } }, +{ "mfcmph", XSPR(31,339,155), XSPR_MASK, PPC860, { RT } }, +{ "mflctrl1", XSPR(31,339,156), XSPR_MASK, PPC860, { RT } }, +{ "mflctrl2", XSPR(31,339,157), XSPR_MASK, PPC860, { RT } }, +{ "mfictrl", XSPR(31,339,158), XSPR_MASK, PPC860, { RT } }, +{ "mfbar", XSPR(31,339,159), XSPR_MASK, PPC860, { RT } }, +{ "mfvrsave", XSPR(31,339,256), XSPR_MASK, PPCVEC, { RT } }, +{ "mfusprg0", XSPR(31,339,256), XSPR_MASK, BOOKE, { RT } }, +{ "mftb", X(31,371), X_MASK, CLASSIC, { RT, TBR } }, +{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, +{ "mftbl", XSPR(31,371,268), XSPR_MASK, CLASSIC, { RT } }, +{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, +{ "mftbu", XSPR(31,371,269), XSPR_MASK, CLASSIC, { RT } }, +{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } }, +{ "mfsprg", XSPR(31,339,256), XSPRG_MASK, PPC, { RT, SPRG } }, +{ "mfsprg0", XSPR(31,339,272), XSPR_MASK, PPC, { RT } }, +{ "mfsprg1", XSPR(31,339,273), XSPR_MASK, PPC, { RT } }, +{ "mfsprg2", XSPR(31,339,274), XSPR_MASK, PPC, { RT } }, +{ "mfsprg3", XSPR(31,339,275), XSPR_MASK, PPC, { RT } }, +{ "mfsprg4", XSPR(31,339,260), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg5", XSPR(31,339,261), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg6", XSPR(31,339,262), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfsprg7", XSPR(31,339,263), XSPR_MASK, PPC405 | BOOKE, { RT } }, +{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC64, { RT } }, +{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, +{ "mfpir", XSPR(31,339,286), XSPR_MASK, BOOKE, { RT } }, +{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, +{ "mfdbsr", XSPR(31,339,304), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbsr", XSPR(31,339,1008), XSPR_MASK, PPC403, { RT } }, +{ "mfdbcr0", XSPR(31,339,308), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbcr0", XSPR(31,339,1010), XSPR_MASK, PPC405, { RT } }, +{ "mfdbcr1", XSPR(31,339,309), XSPR_MASK, BOOKE, { RT } }, +{ "mfdbcr1", XSPR(31,339,957), XSPR_MASK, PPC405, { RT } }, +{ "mfdbcr2", XSPR(31,339,310), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac1", XSPR(31,339,312), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac1", XSPR(31,339,1012), XSPR_MASK, PPC403, { RT } }, +{ "mfiac2", XSPR(31,339,313), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac2", XSPR(31,339,1013), XSPR_MASK, PPC403, { RT } }, +{ "mfiac3", XSPR(31,339,314), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac3", XSPR(31,339,948), XSPR_MASK, PPC405, { RT } }, +{ "mfiac4", XSPR(31,339,315), XSPR_MASK, BOOKE, { RT } }, +{ "mfiac4", XSPR(31,339,949), XSPR_MASK, PPC405, { RT } }, +{ "mfdac1", XSPR(31,339,316), XSPR_MASK, BOOKE, { RT } }, +{ "mfdac1", XSPR(31,339,1014), XSPR_MASK, PPC403, { RT } }, +{ "mfdac2", XSPR(31,339,317), XSPR_MASK, BOOKE, { RT } }, +{ "mfdac2", XSPR(31,339,1015), XSPR_MASK, PPC403, { RT } }, +{ "mfdvc1", XSPR(31,339,318), XSPR_MASK, BOOKE, { RT } }, +{ "mfdvc1", XSPR(31,339,950), XSPR_MASK, PPC405, { RT } }, +{ "mfdvc2", XSPR(31,339,319), XSPR_MASK, BOOKE, { RT } }, +{ "mfdvc2", XSPR(31,339,951), XSPR_MASK, PPC405, { RT } }, +{ "mftsr", XSPR(31,339,336), XSPR_MASK, BOOKE, { RT } }, +{ "mftsr", XSPR(31,339,984), XSPR_MASK, PPC403, { RT } }, +{ "mftcr", XSPR(31,339,340), XSPR_MASK, BOOKE, { RT } }, +{ "mftcr", XSPR(31,339,986), XSPR_MASK, PPC403, { RT } }, +{ "mfivor0", XSPR(31,339,400), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor1", XSPR(31,339,401), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor2", XSPR(31,339,402), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor3", XSPR(31,339,403), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor4", XSPR(31,339,404), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor5", XSPR(31,339,405), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor6", XSPR(31,339,406), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor7", XSPR(31,339,407), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor8", XSPR(31,339,408), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor9", XSPR(31,339,409), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor10", XSPR(31,339,410), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor11", XSPR(31,339,411), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor12", XSPR(31,339,412), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor13", XSPR(31,339,413), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor14", XSPR(31,339,414), XSPR_MASK, BOOKE, { RT } }, +{ "mfivor15", XSPR(31,339,415), XSPR_MASK, BOOKE, { RT } }, +{ "mfspefscr", XSPR(31,339,512), XSPR_MASK, PPCSPE, { RT } }, +{ "mfbbear", XSPR(31,339,513), XSPR_MASK, PPCBRLK, { RT } }, +{ "mfbbtar", XSPR(31,339,514), XSPR_MASK, PPCBRLK, { RT } }, +{ "mfivor32", XSPR(31,339,528), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor33", XSPR(31,339,529), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor34", XSPR(31,339,530), XSPR_MASK, PPCSPE, { RT } }, +{ "mfivor35", XSPR(31,339,531), XSPR_MASK, PPCPMR, { RT } }, +{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfic_cst", XSPR(31,339,560), XSPR_MASK, PPC860, { RT } }, +{ "mfic_adr", XSPR(31,339,561), XSPR_MASK, PPC860, { RT } }, +{ "mfic_dat", XSPR(31,339,562), XSPR_MASK, PPC860, { RT } }, +{ "mfdc_cst", XSPR(31,339,568), XSPR_MASK, PPC860, { RT } }, +{ "mfdc_adr", XSPR(31,339,569), XSPR_MASK, PPC860, { RT } }, +{ "mfmcsrr0", XSPR(31,339,570), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfdc_dat", XSPR(31,339,570), XSPR_MASK, PPC860, { RT } }, +{ "mfmcsrr1", XSPR(31,339,571), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfmcsr", XSPR(31,339,572), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfmcar", XSPR(31,339,573), XSPR_MASK, PPCRFMCI, { RT } }, +{ "mfdpdr", XSPR(31,339,630), XSPR_MASK, PPC860, { RT } }, +{ "mfdpir", XSPR(31,339,631), XSPR_MASK, PPC860, { RT } }, +{ "mfimmr", XSPR(31,339,638), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_ctr", XSPR(31,339,784), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_ap", XSPR(31,339,786), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_epn", XSPR(31,339,787), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_twc", XSPR(31,339,789), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_rpn", XSPR(31,339,790), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_ctr", XSPR(31,339,792), XSPR_MASK, PPC860, { RT } }, +{ "mfm_casid", XSPR(31,339,793), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_ap", XSPR(31,339,794), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_epn", XSPR(31,339,795), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_twb", XSPR(31,339,796), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_twc", XSPR(31,339,797), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_rpn", XSPR(31,339,798), XSPR_MASK, PPC860, { RT } }, +{ "mfm_tw", XSPR(31,339,799), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbcam", XSPR(31,339,816), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbram0",XSPR(31,339,817), XSPR_MASK, PPC860, { RT } }, +{ "mfmi_dbram1",XSPR(31,339,818), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbcam", XSPR(31,339,824), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbram0",XSPR(31,339,825), XSPR_MASK, PPC860, { RT } }, +{ "mfmd_dbram1",XSPR(31,339,826), XSPR_MASK, PPC860, { RT } }, +{ "mfummcr0", XSPR(31,339,936), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc1", XSPR(31,339,937), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc2", XSPR(31,339,938), XSPR_MASK, PPC750, { RT } }, +{ "mfusia", XSPR(31,339,939), XSPR_MASK, PPC750, { RT } }, +{ "mfummcr1", XSPR(31,339,940), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc3", XSPR(31,339,941), XSPR_MASK, PPC750, { RT } }, +{ "mfupmc4", XSPR(31,339,942), XSPR_MASK, PPC750, { RT } }, +{ "mfzpr", XSPR(31,339,944), XSPR_MASK, PPC403, { RT } }, +{ "mfccr0", XSPR(31,339,947), XSPR_MASK, PPC405, { RT } }, +{ "mfmmcr0", XSPR(31,339,952), XSPR_MASK, PPC750, { RT } }, +{ "mfpmc1", XSPR(31,339,953), XSPR_MASK, PPC750, { RT } }, +{ "mfsgr", XSPR(31,339,953), XSPR_MASK, PPC403, { RT } }, +{ "mfpmc2", XSPR(31,339,954), XSPR_MASK, PPC750, { RT } }, +{ "mfdcwr", XSPR(31,339,954), XSPR_MASK, PPC403, { RT } }, +{ "mfsia", XSPR(31,339,955), XSPR_MASK, PPC750, { RT } }, +{ "mfsler", XSPR(31,339,955), XSPR_MASK, PPC405, { RT } }, +{ "mfmmcr1", XSPR(31,339,956), XSPR_MASK, PPC750, { RT } }, +{ "mfsu0r", XSPR(31,339,956), XSPR_MASK, PPC405, { RT } }, +{ "mfpmc3", XSPR(31,339,957), XSPR_MASK, PPC750, { RT } }, +{ "mfpmc4", XSPR(31,339,958), XSPR_MASK, PPC750, { RT } }, +{ "mficdbdr", XSPR(31,339,979), XSPR_MASK, PPC403, { RT } }, +{ "mfevpr", XSPR(31,339,982), XSPR_MASK, PPC403, { RT } }, +{ "mfcdbcr", XSPR(31,339,983), XSPR_MASK, PPC403, { RT } }, +{ "mfpit", XSPR(31,339,987), XSPR_MASK, PPC403, { RT } }, +{ "mftbhi", XSPR(31,339,988), XSPR_MASK, PPC403, { RT } }, +{ "mftblo", XSPR(31,339,989), XSPR_MASK, PPC403, { RT } }, +{ "mfsrr2", XSPR(31,339,990), XSPR_MASK, PPC403, { RT } }, +{ "mfsrr3", XSPR(31,339,991), XSPR_MASK, PPC403, { RT } }, +{ "mfl2cr", XSPR(31,339,1017), XSPR_MASK, PPC750, { RT } }, +{ "mfdccr", XSPR(31,339,1018), XSPR_MASK, PPC403, { RT } }, +{ "mficcr", XSPR(31,339,1019), XSPR_MASK, PPC403, { RT } }, +{ "mfictc", XSPR(31,339,1019), XSPR_MASK, PPC750, { RT } }, +{ "mfpbl1", XSPR(31,339,1020), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm1", XSPR(31,339,1020), XSPR_MASK, PPC750, { RT } }, +{ "mfpbu1", XSPR(31,339,1021), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm2", XSPR(31,339,1021), XSPR_MASK, PPC750, { RT } }, +{ "mfpbl2", XSPR(31,339,1022), XSPR_MASK, PPC403, { RT } }, +{ "mfthrm3", XSPR(31,339,1022), XSPR_MASK, PPC750, { RT } }, +{ "mfpbu2", XSPR(31,339,1023), XSPR_MASK, PPC403, { RT } }, +{ "mfspr", X(31,339), X_MASK, COM, { RT, SPR } }, + +{ "lwax", X(31,341), X_MASK, PPC64, { RT, RA0, RB } }, + +{ "dst", XDSS(31,342,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, +{ "dstt", XDSS(31,342,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, + +{ "lhax", X(31,343), X_MASK, COM, { RT, RA0, RB } }, + +{ "lhaxe", X(31,351), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "dstst", XDSS(31,374,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, +{ "dststt", XDSS(31,374,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, + +{ "dccci", X(31,454), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "abs", XO(31,360,0,0), XORB_MASK, M601, { RT, RA } }, +{ "abs.", XO(31,360,0,1), XORB_MASK, M601, { RT, RA } }, +{ "abso", XO(31,360,1,0), XORB_MASK, M601, { RT, RA } }, +{ "abso.", XO(31,360,1,1), XORB_MASK, M601, { RT, RA } }, + +{ "divs", XO(31,363,0,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divs.", XO(31,363,0,1), XO_MASK, M601, { RT, RA, RB } }, +{ "divso", XO(31,363,1,0), XO_MASK, M601, { RT, RA, RB } }, +{ "divso.", XO(31,363,1,1), XO_MASK, M601, { RT, RA, RB } }, + +{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, + +{ "lwaux", X(31,373), X_MASK, PPC64, { RT, RAL, RB } }, + +{ "lhaux", X(31,375), X_MASK, COM, { RT, RAL, RB } }, + +{ "lhauxe", X(31,383), X_MASK, BOOKE64, { RT, RAL, RB } }, + +{ "mtdcrx", X(31,387), X_MASK, BOOKE, { RA, RS } }, + +{ "dcblc", X(31,390), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "subfe64", XO(31,392,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, +{ "subfe64o",XO(31,392,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, + +{ "adde64", XO(31,394,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, +{ "adde64o", XO(31,394,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, + +{ "dcblce", X(31,398), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "slbmte", X(31,402), XRA_MASK, PPC64, { RS, RB } }, + +{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } }, + +{ "cmpb", X(31,508), X_MASK, POWER6, { RA, RS, RB } }, + +{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "lfdpx", X(31,791), X_MASK, POWER6, { FRT, RA, RB } }, + +{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "stfdpx", X(31,919), X_MASK, POWER6, { FRS, RA, RB } }, + +{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "orc", XRC(31,412,0), X_MASK, COM, { RA, RS, RB } }, +{ "orc.", XRC(31,412,1), X_MASK, COM, { RA, RS, RB } }, + +{ "sradi", XS(31,413,0), XS_MASK, PPC64, { RA, RS, SH6 } }, +{ "sradi.", XS(31,413,1), XS_MASK, PPC64, { RA, RS, SH6 } }, + +{ "sthxe", X(31,415), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "slbie", X(31,434), XRTRA_MASK, PPC64, { RB } }, + +{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, + +{ "sthux", X(31,439), X_MASK, COM, { RS, RAS, RB } }, + +{ "sthuxe", X(31,447), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "cctpl", 0x7c210b78, 0xffffffff, CELL, { 0 }}, +{ "cctpm", 0x7c421378, 0xffffffff, CELL, { 0 }}, +{ "cctph", 0x7c631b78, 0xffffffff, CELL, { 0 }}, +{ "db8cyc", 0x7f9ce378, 0xffffffff, CELL, { 0 }}, +{ "db10cyc", 0x7fbdeb78, 0xffffffff, CELL, { 0 }}, +{ "db12cyc", 0x7fdef378, 0xffffffff, CELL, { 0 }}, +{ "db16cyc", 0x7ffffb78, 0xffffffff, CELL, { 0 }}, +{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } }, +{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } }, +{ "mr.", XRC(31,444,1), X_MASK, COM, { RA, RS, RBS } }, +{ "or.", XRC(31,444,1), X_MASK, COM, { RA, RS, RB } }, + +{ "mtexisr", XSPR(31,451,64), XSPR_MASK, PPC403, { RS } }, +{ "mtexier", XSPR(31,451,66), XSPR_MASK, PPC403, { RS } }, +{ "mtbr0", XSPR(31,451,128), XSPR_MASK, PPC403, { RS } }, +{ "mtbr1", XSPR(31,451,129), XSPR_MASK, PPC403, { RS } }, +{ "mtbr2", XSPR(31,451,130), XSPR_MASK, PPC403, { RS } }, +{ "mtbr3", XSPR(31,451,131), XSPR_MASK, PPC403, { RS } }, +{ "mtbr4", XSPR(31,451,132), XSPR_MASK, PPC403, { RS } }, +{ "mtbr5", XSPR(31,451,133), XSPR_MASK, PPC403, { RS } }, +{ "mtbr6", XSPR(31,451,134), XSPR_MASK, PPC403, { RS } }, +{ "mtbr7", XSPR(31,451,135), XSPR_MASK, PPC403, { RS } }, +{ "mtbear", XSPR(31,451,144), XSPR_MASK, PPC403, { RS } }, +{ "mtbesr", XSPR(31,451,145), XSPR_MASK, PPC403, { RS } }, +{ "mtiocr", XSPR(31,451,160), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403, { RS } }, +{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403, { RS } }, +{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403, { RS } }, +{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403, { RS } }, +{ "mtdmasr", XSPR(31,451,224), XSPR_MASK, PPC403, { RS } }, +{ "mtdcr", X(31,451), X_MASK, PPC403 | BOOKE, { SPR, RS } }, + +{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divdu", XO(31,457,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdu.", XO(31,457,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divduo", XO(31,457,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divduo.", XO(31,457,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mtmq", XSPR(31,467,0), XSPR_MASK, M601, { RS } }, +{ "mtxer", XSPR(31,467,1), XSPR_MASK, COM, { RS } }, +{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } }, +{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } }, +{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, +{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, COM, { RS } }, +{ "mtdar", XSPR(31,467,19), XSPR_MASK, COM, { RS } }, +{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, COM, { RS } }, +{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, COM, { RS } }, +{ "mtdec", XSPR(31,467,22), XSPR_MASK, COM, { RS } }, +{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, +{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, COM, { RS } }, +{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, COM, { RS } }, +{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, COM, { RS } }, +{ "mtcfar", XSPR(31,467,28), XSPR_MASK, POWER6, { RS } }, +{ "mtpid", XSPR(31,467,48), XSPR_MASK, BOOKE, { RS } }, +{ "mtpid", XSPR(31,467,945), XSPR_MASK, PPC403, { RS } }, +{ "mtdecar", XSPR(31,467,54), XSPR_MASK, BOOKE, { RS } }, +{ "mtcsrr0", XSPR(31,467,58), XSPR_MASK, BOOKE, { RS } }, +{ "mtcsrr1", XSPR(31,467,59), XSPR_MASK, BOOKE, { RS } }, +{ "mtdear", XSPR(31,467,61), XSPR_MASK, BOOKE, { RS } }, +{ "mtdear", XSPR(31,467,981), XSPR_MASK, PPC403, { RS } }, +{ "mtesr", XSPR(31,467,62), XSPR_MASK, BOOKE, { RS } }, +{ "mtesr", XSPR(31,467,980), XSPR_MASK, PPC403, { RS } }, +{ "mtivpr", XSPR(31,467,63), XSPR_MASK, BOOKE, { RS } }, +{ "mtcmpa", XSPR(31,467,144), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpb", XSPR(31,467,145), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpc", XSPR(31,467,146), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpd", XSPR(31,467,147), XSPR_MASK, PPC860, { RS } }, +{ "mticr", XSPR(31,467,148), XSPR_MASK, PPC860, { RS } }, +{ "mtder", XSPR(31,467,149), XSPR_MASK, PPC860, { RS } }, +{ "mtcounta", XSPR(31,467,150), XSPR_MASK, PPC860, { RS } }, +{ "mtcountb", XSPR(31,467,151), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpe", XSPR(31,467,152), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpf", XSPR(31,467,153), XSPR_MASK, PPC860, { RS } }, +{ "mtcmpg", XSPR(31,467,154), XSPR_MASK, PPC860, { RS } }, +{ "mtcmph", XSPR(31,467,155), XSPR_MASK, PPC860, { RS } }, +{ "mtlctrl1", XSPR(31,467,156), XSPR_MASK, PPC860, { RS } }, +{ "mtlctrl2", XSPR(31,467,157), XSPR_MASK, PPC860, { RS } }, +{ "mtictrl", XSPR(31,467,158), XSPR_MASK, PPC860, { RS } }, +{ "mtbar", XSPR(31,467,159), XSPR_MASK, PPC860, { RS } }, +{ "mtvrsave", XSPR(31,467,256), XSPR_MASK, PPCVEC, { RS } }, +{ "mtusprg0", XSPR(31,467,256), XSPR_MASK, BOOKE, { RS } }, +{ "mtsprg", XSPR(31,467,256), XSPRG_MASK,PPC, { SPRG, RS } }, +{ "mtsprg0", XSPR(31,467,272), XSPR_MASK, PPC, { RS } }, +{ "mtsprg1", XSPR(31,467,273), XSPR_MASK, PPC, { RS } }, +{ "mtsprg2", XSPR(31,467,274), XSPR_MASK, PPC, { RS } }, +{ "mtsprg3", XSPR(31,467,275), XSPR_MASK, PPC, { RS } }, +{ "mtsprg4", XSPR(31,467,276), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg5", XSPR(31,467,277), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg6", XSPR(31,467,278), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtsprg7", XSPR(31,467,279), XSPR_MASK, PPC405 | BOOKE, { RS } }, +{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC64, { RS } }, +{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, +{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, +{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, +{ "mtdbsr", XSPR(31,467,304), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbsr", XSPR(31,467,1008), XSPR_MASK, PPC403, { RS } }, +{ "mtdbcr0", XSPR(31,467,308), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbcr0", XSPR(31,467,1010), XSPR_MASK, PPC405, { RS } }, +{ "mtdbcr1", XSPR(31,467,309), XSPR_MASK, BOOKE, { RS } }, +{ "mtdbcr1", XSPR(31,467,957), XSPR_MASK, PPC405, { RS } }, +{ "mtdbcr2", XSPR(31,467,310), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac1", XSPR(31,467,312), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac1", XSPR(31,467,1012), XSPR_MASK, PPC403, { RS } }, +{ "mtiac2", XSPR(31,467,313), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac2", XSPR(31,467,1013), XSPR_MASK, PPC403, { RS } }, +{ "mtiac3", XSPR(31,467,314), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac3", XSPR(31,467,948), XSPR_MASK, PPC405, { RS } }, +{ "mtiac4", XSPR(31,467,315), XSPR_MASK, BOOKE, { RS } }, +{ "mtiac4", XSPR(31,467,949), XSPR_MASK, PPC405, { RS } }, +{ "mtdac1", XSPR(31,467,316), XSPR_MASK, BOOKE, { RS } }, +{ "mtdac1", XSPR(31,467,1014), XSPR_MASK, PPC403, { RS } }, +{ "mtdac2", XSPR(31,467,317), XSPR_MASK, BOOKE, { RS } }, +{ "mtdac2", XSPR(31,467,1015), XSPR_MASK, PPC403, { RS } }, +{ "mtdvc1", XSPR(31,467,318), XSPR_MASK, BOOKE, { RS } }, +{ "mtdvc1", XSPR(31,467,950), XSPR_MASK, PPC405, { RS } }, +{ "mtdvc2", XSPR(31,467,319), XSPR_MASK, BOOKE, { RS } }, +{ "mtdvc2", XSPR(31,467,951), XSPR_MASK, PPC405, { RS } }, +{ "mttsr", XSPR(31,467,336), XSPR_MASK, BOOKE, { RS } }, +{ "mttsr", XSPR(31,467,984), XSPR_MASK, PPC403, { RS } }, +{ "mttcr", XSPR(31,467,340), XSPR_MASK, BOOKE, { RS } }, +{ "mttcr", XSPR(31,467,986), XSPR_MASK, PPC403, { RS } }, +{ "mtivor0", XSPR(31,467,400), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor1", XSPR(31,467,401), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor2", XSPR(31,467,402), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor3", XSPR(31,467,403), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor4", XSPR(31,467,404), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor5", XSPR(31,467,405), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor6", XSPR(31,467,406), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor7", XSPR(31,467,407), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor8", XSPR(31,467,408), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor9", XSPR(31,467,409), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor10", XSPR(31,467,410), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor11", XSPR(31,467,411), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor12", XSPR(31,467,412), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor13", XSPR(31,467,413), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor14", XSPR(31,467,414), XSPR_MASK, BOOKE, { RS } }, +{ "mtivor15", XSPR(31,467,415), XSPR_MASK, BOOKE, { RS } }, +{ "mtspefscr", XSPR(31,467,512), XSPR_MASK, PPCSPE, { RS } }, +{ "mtbbear", XSPR(31,467,513), XSPR_MASK, PPCBRLK, { RS } }, +{ "mtbbtar", XSPR(31,467,514), XSPR_MASK, PPCBRLK, { RS } }, +{ "mtivor32", XSPR(31,467,528), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor33", XSPR(31,467,529), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor34", XSPR(31,467,530), XSPR_MASK, PPCSPE, { RS } }, +{ "mtivor35", XSPR(31,467,531), XSPR_MASK, PPCPMR, { RS } }, +{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtmcsrr0", XSPR(31,467,570), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtmcsrr1", XSPR(31,467,571), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtmcsr", XSPR(31,467,572), XSPR_MASK, PPCRFMCI, { RS } }, +{ "mtummcr0", XSPR(31,467,936), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc1", XSPR(31,467,937), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc2", XSPR(31,467,938), XSPR_MASK, PPC750, { RS } }, +{ "mtusia", XSPR(31,467,939), XSPR_MASK, PPC750, { RS } }, +{ "mtummcr1", XSPR(31,467,940), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc3", XSPR(31,467,941), XSPR_MASK, PPC750, { RS } }, +{ "mtupmc4", XSPR(31,467,942), XSPR_MASK, PPC750, { RS } }, +{ "mtzpr", XSPR(31,467,944), XSPR_MASK, PPC403, { RS } }, +{ "mtccr0", XSPR(31,467,947), XSPR_MASK, PPC405, { RS } }, +{ "mtmmcr0", XSPR(31,467,952), XSPR_MASK, PPC750, { RS } }, +{ "mtsgr", XSPR(31,467,953), XSPR_MASK, PPC403, { RS } }, +{ "mtpmc1", XSPR(31,467,953), XSPR_MASK, PPC750, { RS } }, +{ "mtdcwr", XSPR(31,467,954), XSPR_MASK, PPC403, { RS } }, +{ "mtpmc2", XSPR(31,467,954), XSPR_MASK, PPC750, { RS } }, +{ "mtsler", XSPR(31,467,955), XSPR_MASK, PPC405, { RS } }, +{ "mtsia", XSPR(31,467,955), XSPR_MASK, PPC750, { RS } }, +{ "mtsu0r", XSPR(31,467,956), XSPR_MASK, PPC405, { RS } }, +{ "mtmmcr1", XSPR(31,467,956), XSPR_MASK, PPC750, { RS } }, +{ "mtpmc3", XSPR(31,467,957), XSPR_MASK, PPC750, { RS } }, +{ "mtpmc4", XSPR(31,467,958), XSPR_MASK, PPC750, { RS } }, +{ "mticdbdr", XSPR(31,467,979), XSPR_MASK, PPC403, { RS } }, +{ "mtevpr", XSPR(31,467,982), XSPR_MASK, PPC403, { RS } }, +{ "mtcdbcr", XSPR(31,467,983), XSPR_MASK, PPC403, { RS } }, +{ "mtpit", XSPR(31,467,987), XSPR_MASK, PPC403, { RS } }, +{ "mttbhi", XSPR(31,467,988), XSPR_MASK, PPC403, { RS } }, +{ "mttblo", XSPR(31,467,989), XSPR_MASK, PPC403, { RS } }, +{ "mtsrr2", XSPR(31,467,990), XSPR_MASK, PPC403, { RS } }, +{ "mtsrr3", XSPR(31,467,991), XSPR_MASK, PPC403, { RS } }, +{ "mtl2cr", XSPR(31,467,1017), XSPR_MASK, PPC750, { RS } }, +{ "mtdccr", XSPR(31,467,1018), XSPR_MASK, PPC403, { RS } }, +{ "mticcr", XSPR(31,467,1019), XSPR_MASK, PPC403, { RS } }, +{ "mtictc", XSPR(31,467,1019), XSPR_MASK, PPC750, { RS } }, +{ "mtpbl1", XSPR(31,467,1020), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm1", XSPR(31,467,1020), XSPR_MASK, PPC750, { RS } }, +{ "mtpbu1", XSPR(31,467,1021), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm2", XSPR(31,467,1021), XSPR_MASK, PPC750, { RS } }, +{ "mtpbl2", XSPR(31,467,1022), XSPR_MASK, PPC403, { RS } }, +{ "mtthrm3", XSPR(31,467,1022), XSPR_MASK, PPC750, { RS } }, +{ "mtpbu2", XSPR(31,467,1023), XSPR_MASK, PPC403, { RS } }, +{ "mtspr", X(31,467), X_MASK, COM, { SPR, RS } }, + +{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, + +{ "nand", XRC(31,476,0), X_MASK, COM, { RA, RS, RB } }, +{ "nand.", XRC(31,476,1), X_MASK, COM, { RA, RS, RB } }, + +{ "dcbie", X(31,478), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "dcread", X(31,486), X_MASK, PPC403|PPC440, { RT, RA, RB }}, + +{ "mtpmr", X(31,462), X_MASK, PPCPMR, { PMR, RS }}, + +{ "icbtls", X(31,486), X_MASK, PPCCHLK, { CT, RA, RB }}, + +{ "nabs", XO(31,488,0,0), XORB_MASK, M601, { RT, RA } }, +{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "nabs.", XO(31,488,0,1), XORB_MASK, M601, { RT, RA } }, +{ "nabso", XO(31,488,1,0), XORB_MASK, M601, { RT, RA } }, +{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "nabso.", XO(31,488,1,1), XORB_MASK, M601, { RT, RA } }, + +{ "divd", XO(31,489,0,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divd.", XO(31,489,0,1), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdo", XO(31,489,1,0), XO_MASK, PPC64, { RT, RA, RB } }, +{ "divdo.", XO(31,489,1,1), XO_MASK, PPC64, { RT, RA, RB } }, + +{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64, { RT, RA } }, +{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64, { RT, RA } }, + +{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "icbtlse", X(31,494), X_MASK, PPCCHLK64, { CT, RA, RB }}, + +{ "slbia", X(31,498), 0xffffffff, PPC64, { 0 } }, + +{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, + +{ "stdcxe.", XRC(31,511,1), X_MASK, BOOKE64, { RS, RA, RB } }, + +{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), COM, { BF } }, + +{ "bblels", X(31,518), X_MASK, PPCBRLK, { 0 }}, +{ "mcrxr64", X(31,544), XRARB_MASK|(3<<21), BOOKE64, { BF } }, + +{ "clcs", X(31,531), XRB_MASK, M601, { RT, RA } }, + +{ "ldbrx", X(31,532), X_MASK, CELL, { RT, RA0, RB } }, + +{ "lswx", X(31,533), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lsx", X(31,533), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lwbrx", X(31,534), X_MASK, PPCCOM, { RT, RA0, RB } }, +{ "lbrx", X(31,534), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } }, + +{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sr", XRC(31,536,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "srw.", XRC(31,536,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sr.", XRC(31,536,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "rrib", XRC(31,537,0), X_MASK, M601, { RA, RS, RB } }, +{ "rrib.", XRC(31,537,1), X_MASK, M601, { RA, RS, RB } }, + +{ "srd", XRC(31,539,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "srd.", XRC(31,539,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "maskir", XRC(31,541,0), X_MASK, M601, { RA, RS, RB } }, +{ "maskir.", XRC(31,541,1), X_MASK, M601, { RA, RS, RB } }, + +{ "lwbrxe", X(31,542), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "lfsxe", X(31,543), X_MASK, BOOKE64, { FRT, RA0, RB } }, + +{ "bbelr", X(31,550), X_MASK, PPCBRLK, { 0 }}, + +{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, + +{ "lfsux", X(31,567), X_MASK, COM, { FRT, RAS, RB } }, + +{ "lfsuxe", X(31,575), X_MASK, BOOKE64, { FRT, RAS, RB } }, + +{ "mfsr", X(31,595), XRB_MASK|(1<<20), COM32, { RT, SR } }, + +{ "lswi", X(31,597), X_MASK, PPCCOM, { RT, RA0, NB } }, +{ "lsi", X(31,597), X_MASK, PWRCOM, { RT, RA0, NB } }, + +{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPC, { 0 } }, +{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64, { 0 } }, +{ "msync", X(31,598), 0xffffffff, BOOKE, { 0 } }, +{ "sync", X(31,598), XSYNC_MASK, PPCCOM, { LS } }, +{ "dcs", X(31,598), 0xffffffff, PWRCOM, { 0 } }, + +{ "lfdx", X(31,599), X_MASK, COM, { FRT, RA0, RB } }, + +{ "lfdxe", X(31,607), X_MASK, BOOKE64, { FRT, RA0, RB } }, + +{ "mffgpr", XRC(31,607,0), XRA_MASK, POWER6, { FRT, RB } }, + +{ "mfsri", X(31,627), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "dclst", X(31,630), XRB_MASK, PWRCOM, { RS, RA } }, + +{ "lfdux", X(31,631), X_MASK, COM, { FRT, RAS, RB } }, + +{ "lfduxe", X(31,639), X_MASK, BOOKE64, { FRT, RAS, RB } }, + +{ "mfsrin", X(31,659), XRA_MASK, PPC32, { RT, RB } }, + +{ "stdbrx", X(31,660), X_MASK, CELL, { RS, RA0, RB } }, + +{ "stswx", X(31,661), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stsx", X(31,661), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "stwbrx", X(31,662), X_MASK, PPCCOM, { RS, RA0, RB } }, +{ "stbrx", X(31,662), X_MASK, PWRCOM, { RS, RA0, RB } }, + +{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } }, + +{ "srq", XRC(31,664,0), X_MASK, M601, { RA, RS, RB } }, +{ "srq.", XRC(31,664,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sre", XRC(31,665,0), X_MASK, M601, { RA, RS, RB } }, +{ "sre.", XRC(31,665,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stwbrxe", X(31,670), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stfsxe", X(31,671), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "stfsux", X(31,695), X_MASK, COM, { FRS, RAS, RB } }, + +{ "sriq", XRC(31,696,0), X_MASK, M601, { RA, RS, SH } }, +{ "sriq.", XRC(31,696,1), X_MASK, M601, { RA, RS, SH } }, + +{ "stfsuxe", X(31,703), X_MASK, BOOKE64, { FRS, RAS, RB } }, + +{ "stswi", X(31,725), X_MASK, PPCCOM, { RS, RA0, NB } }, +{ "stsi", X(31,725), X_MASK, PWRCOM, { RS, RA0, NB } }, + +{ "stfdx", X(31,727), X_MASK, COM, { FRS, RA0, RB } }, + +{ "srlq", XRC(31,728,0), X_MASK, M601, { RA, RS, RB } }, +{ "srlq.", XRC(31,728,1), X_MASK, M601, { RA, RS, RB } }, + +{ "sreq", XRC(31,729,0), X_MASK, M601, { RA, RS, RB } }, +{ "sreq.", XRC(31,729,1), X_MASK, M601, { RA, RS, RB } }, + +{ "stfdxe", X(31,735), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "mftgpr", XRC(31,735,0), XRA_MASK, POWER6, { RT, FRB } }, + +{ "dcba", X(31,758), XRT_MASK, PPC405 | BOOKE, { RA, RB } }, + +{ "stfdux", X(31,759), X_MASK, COM, { FRS, RAS, RB } }, + +{ "srliq", XRC(31,760,0), X_MASK, M601, { RA, RS, SH } }, +{ "srliq.", XRC(31,760,1), X_MASK, M601, { RA, RS, SH } }, + +{ "dcbae", X(31,766), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "stfduxe", X(31,767), X_MASK, BOOKE64, { FRS, RAS, RB } }, + +{ "tlbivax", X(31,786), XRT_MASK, BOOKE, { RA, RB } }, +{ "tlbivaxe",X(31,787), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lwzcix", X(31,789), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "lhbrx", X(31,790), X_MASK, COM, { RT, RA0, RB } }, + +{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sra", XRC(31,792,0), X_MASK, PWRCOM, { RA, RS, RB } }, +{ "sraw.", XRC(31,792,1), X_MASK, PPCCOM, { RA, RS, RB } }, +{ "sra.", XRC(31,792,1), X_MASK, PWRCOM, { RA, RS, RB } }, + +{ "srad", XRC(31,794,0), X_MASK, PPC64, { RA, RS, RB } }, +{ "srad.", XRC(31,794,1), X_MASK, PPC64, { RA, RS, RB } }, + +{ "lhbrxe", X(31,798), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "ldxe", X(31,799), X_MASK, BOOKE64, { RT, RA0, RB } }, +{ "lduxe", X(31,831), X_MASK, BOOKE64, { RT, RA0, RB } }, + +{ "rac", X(31,818), X_MASK, PWRCOM, { RT, RA, RB } }, + +{ "lhzcix", X(31,821), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "dss", XDSS(31,822,0), XDSS_MASK, PPCVEC, { STRM } }, +{ "dssall", XDSS(31,822,1), XDSS_MASK, PPCVEC, { 0 } }, + +{ "srawi", XRC(31,824,0), X_MASK, PPCCOM, { RA, RS, SH } }, +{ "srai", XRC(31,824,0), X_MASK, PWRCOM, { RA, RS, SH } }, +{ "srawi.", XRC(31,824,1), X_MASK, PPCCOM, { RA, RS, SH } }, +{ "srai.", XRC(31,824,1), X_MASK, PWRCOM, { RA, RS, SH } }, + +{ "slbmfev", X(31,851), XRA_MASK, PPC64, { RT, RB } }, + +{ "lbzcix", X(31,853), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "mbar", X(31,854), X_MASK, BOOKE, { MO } }, +{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, + +{ "lfiwax", X(31,855), X_MASK, POWER6, { FRT, RA0, RB } }, + +{ "ldcix", X(31,885), X_MASK, POWER6, { RT, RA0, RB } }, + +{ "tlbsx", XRC(31,914,0), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, +{ "tlbsx.", XRC(31,914,1), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, +{ "tlbsxe", XRC(31,915,0), X_MASK, BOOKE64, { RTO, RA, RB } }, +{ "tlbsxe.", XRC(31,915,1), X_MASK, BOOKE64, { RTO, RA, RB } }, + +{ "slbmfee", X(31,915), XRA_MASK, PPC64, { RT, RB } }, + +{ "stwcix", X(31,917), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "sthbrx", X(31,918), X_MASK, COM, { RS, RA0, RB } }, + +{ "sraq", XRC(31,920,0), X_MASK, M601, { RA, RS, RB } }, +{ "sraq.", XRC(31,920,1), X_MASK, M601, { RA, RS, RB } }, + +{ "srea", XRC(31,921,0), X_MASK, M601, { RA, RS, RB } }, +{ "srea.", XRC(31,921,1), X_MASK, M601, { RA, RS, RB } }, + +{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } }, +{ "exts", XRC(31,922,0), XRB_MASK, PWRCOM, { RA, RS } }, +{ "extsh.", XRC(31,922,1), XRB_MASK, PPCCOM, { RA, RS } }, +{ "exts.", XRC(31,922,1), XRB_MASK, PWRCOM, { RA, RS } }, + +{ "sthbrxe", X(31,926), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "stdxe", X(31,927), X_MASK, BOOKE64, { RS, RA0, RB } }, + +{ "tlbrehi", XTLB(31,946,0), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbrelo", XTLB(31,946,1), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbre", X(31,946), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, + +{ "sthcix", X(31,949), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "sraiq", XRC(31,952,0), X_MASK, M601, { RA, RS, SH } }, +{ "sraiq.", XRC(31,952,1), X_MASK, M601, { RA, RS, SH } }, + +{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, +{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, + +{ "stduxe", X(31,959), X_MASK, BOOKE64, { RS, RAS, RB } }, + +{ "iccci", X(31,966), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "tlbwehi", XTLB(31,978,0), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbwelo", XTLB(31,978,1), XTLB_MASK, PPC403, { RT, RA } }, +{ "tlbwe", X(31,978), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, +{ "tlbld", X(31,978), XRTRA_MASK, PPC, { RB } }, + +{ "stbcix", X(31,981), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, + +{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA0, RB } }, + +{ "extsw", XRC(31,986,0), XRB_MASK, PPC64 | BOOKE64,{ RA, RS } }, +{ "extsw.", XRC(31,986,1), XRB_MASK, PPC64, { RA, RS } }, + +{ "icread", X(31,998), XRT_MASK, PPC403|PPC440, { RA, RB } }, + +{ "icbie", X(31,990), XRT_MASK, BOOKE64, { RA, RB } }, +{ "stfiwxe", X(31,991), X_MASK, BOOKE64, { FRS, RA0, RB } }, + +{ "tlbli", X(31,1010), XRTRA_MASK, PPC, { RB } }, + +{ "stdcix", X(31,1013), X_MASK, POWER6, { RS, RA0, RB } }, + +{ "dcbzl", XOPL(31,1014,1), XRT_MASK,POWER4, { RA, RB } }, +{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, +{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, + +{ "dcbze", X(31,1022), XRT_MASK, BOOKE64, { RA, RB } }, + +{ "lvebx", X(31, 7), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvehx", X(31, 39), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvewx", X(31, 71), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvsl", X(31, 6), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvsr", X(31, 38), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvx", X(31, 103), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "lvxl", X(31, 359), X_MASK, PPCVEC, { VD, RA, RB } }, +{ "stvebx", X(31, 135), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvehx", X(31, 167), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvewx", X(31, 199), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvx", X(31, 231), X_MASK, PPCVEC, { VS, RA, RB } }, +{ "stvxl", X(31, 487), X_MASK, PPCVEC, { VS, RA, RB } }, + +/* New load/store left/right index vector instructions that are in the Cell only. */ +{ "lvlx", X(31, 519), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvlxl", X(31, 775), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvrx", X(31, 551), X_MASK, CELL, { VD, RA0, RB } }, +{ "lvrxl", X(31, 807), X_MASK, CELL, { VD, RA0, RB } }, +{ "stvlx", X(31, 647), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvlxl", X(31, 903), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvrx", X(31, 679), X_MASK, CELL, { VS, RA0, RB } }, +{ "stvrxl", X(31, 935), X_MASK, CELL, { VS, RA0, RB } }, + +{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } }, +{ "l", OP(32), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "lwzu", OP(33), OP_MASK, PPCCOM, { RT, D, RAL } }, +{ "lu", OP(33), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lbzu", OP(35), OP_MASK, COM, { RT, D, RAL } }, + +{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } }, +{ "st", OP(36), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } }, +{ "stu", OP(37), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } }, + +{ "stbu", OP(39), OP_MASK, COM, { RS, D, RAS } }, + +{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lhzu", OP(41), OP_MASK, COM, { RT, D, RAL } }, + +{ "lha", OP(42), OP_MASK, COM, { RT, D, RA0 } }, + +{ "lhau", OP(43), OP_MASK, COM, { RT, D, RAL } }, + +{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } }, + +{ "sthu", OP(45), OP_MASK, COM, { RS, D, RAS } }, + +{ "lmw", OP(46), OP_MASK, PPCCOM, { RT, D, RAM } }, +{ "lm", OP(46), OP_MASK, PWRCOM, { RT, D, RA0 } }, + +{ "stmw", OP(47), OP_MASK, PPCCOM, { RS, D, RA0 } }, +{ "stm", OP(47), OP_MASK, PWRCOM, { RS, D, RA0 } }, + +{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } }, + +{ "lfsu", OP(49), OP_MASK, COM, { FRT, D, RAS } }, + +{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } }, + +{ "lfdu", OP(51), OP_MASK, COM, { FRT, D, RAS } }, + +{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } }, + +{ "stfsu", OP(53), OP_MASK, COM, { FRS, D, RAS } }, + +{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } }, + +{ "stfdu", OP(55), OP_MASK, COM, { FRS, D, RAS } }, + +{ "lq", OP(56), OP_MASK, POWER4, { RTQ, DQ, RAQ } }, + +{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA0 } }, + +{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA0 } }, + +{ "lfdp", OP(57), OP_MASK, POWER6, { FRT, D, RA0 } }, + +{ "lbze", DEO(58,0), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lbzue", DEO(58,1), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lhze", DEO(58,2), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lhzue", DEO(58,3), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lhae", DEO(58,4), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lhaue", DEO(58,5), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "lwze", DEO(58,6), DE_MASK, BOOKE64, { RT, DE, RA0 } }, +{ "lwzue", DEO(58,7), DE_MASK, BOOKE64, { RT, DE, RAL } }, +{ "stbe", DEO(58,8), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "stbue", DEO(58,9), DE_MASK, BOOKE64, { RS, DE, RAS } }, +{ "sthe", DEO(58,10), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "sthue", DEO(58,11), DE_MASK, BOOKE64, { RS, DE, RAS } }, +{ "stwe", DEO(58,14), DE_MASK, BOOKE64, { RS, DE, RA0 } }, +{ "stwue", DEO(58,15), DE_MASK, BOOKE64, { RS, DE, RAS } }, + +{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } }, + +{ "ldu", DSO(58,1), DS_MASK, PPC64, { RT, DS, RAL } }, + +{ "lwa", DSO(58,2), DS_MASK, PPC64, { RT, DS, RA0 } }, + +{ "dadd", XRC(59,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dadd.", XRC(59,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dqua", ZRC(59,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "dqua.", ZRC(59,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fres", A(59,24,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, +{ "fres.", A(59,24,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, + +{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, + +{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, +{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, + +{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "dmul", XRC(59,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dmul.", XRC(59,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "drrnd", ZRC(59,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "drrnd.", ZRC(59,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "dscli", ZRC(59,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscli.", ZRC(59,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "dquai", ZRC(59,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, +{ "dquai.", ZRC(59,67,1), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, + +{ "dscri", ZRC(59,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscri.", ZRC(59,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "drintx", ZRC(59,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintx.", ZRC(59,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dcmpo", X(59,130), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstex", X(59,162), X_MASK, POWER6, { BF, FRA, FRB } }, +{ "dtstdc", Z(59,194), Z_MASK, POWER6, { BF, FRA, DCM } }, +{ "dtstdg", Z(59,226), Z_MASK, POWER6, { BF, FRA, DGM } }, + +{ "drintn", ZRC(59,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintn.", ZRC(59,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dctdp", XRC(59,258,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctdp.", XRC(59,258,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dctfix", XRC(59,290,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctfix.", XRC(59,290,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "ddedpd", XRC(59,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, +{ "ddedpd.", XRC(59,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, + +{ "dxex", XRC(59,354,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dxex.", XRC(59,354,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dsub", XRC(59,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dsub.", XRC(59,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "ddiv", XRC(59,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "ddiv.", XRC(59,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dcmpu", X(59,642), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstsf", X(59,674), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "drsp", XRC(59,770,0), X_MASK, POWER6, { FRT, FRB } }, +{ "drsp.", XRC(59,770,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dcffix", XRC(59,802,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dcffix.", XRC(59,802,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "denbcd", XRC(59,834,0), X_MASK, POWER6, { S, FRT, FRB } }, +{ "denbcd.", XRC(59,834,1), X_MASK, POWER6, { S, FRT, FRB } }, + +{ "diex", XRC(59,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "diex.", XRC(59,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfdp", OP(61), OP_MASK, POWER6, { FRT, D, RA0 } }, + +{ "lde", DEO(62,0), DE_MASK, BOOKE64, { RT, DES, RA0 } }, +{ "ldue", DEO(62,1), DE_MASK, BOOKE64, { RT, DES, RA0 } }, +{ "lfse", DEO(62,4), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, +{ "lfsue", DEO(62,5), DE_MASK, BOOKE64, { FRT, DES, RAS } }, +{ "lfde", DEO(62,6), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, +{ "lfdue", DEO(62,7), DE_MASK, BOOKE64, { FRT, DES, RAS } }, +{ "stde", DEO(62,8), DE_MASK, BOOKE64, { RS, DES, RA0 } }, +{ "stdue", DEO(62,9), DE_MASK, BOOKE64, { RS, DES, RAS } }, +{ "stfse", DEO(62,12), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, +{ "stfsue", DEO(62,13), DE_MASK, BOOKE64, { FRS, DES, RAS } }, +{ "stfde", DEO(62,14), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, +{ "stfdue", DEO(62,15), DE_MASK, BOOKE64, { FRS, DES, RAS } }, + +{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } }, + +{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } }, + +{ "stq", DSO(62,2), DS_MASK, POWER4, { RSQ, DS, RA0 } }, + +{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, + +{ "daddq", XRC(63,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "daddq.", XRC(63,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "dquaq", ZRC(63,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "dquaq.", ZRC(63,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "fcpsgn", XRC(63,8,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "fcpsgn.", XRC(63,8,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } }, +{ "frsp.", XRC(63,12,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "fctiw", XRC(63,14,0), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiw.", XRC(63,14,1), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPCCOM, { FRT, FRB } }, +{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fdiv", A(63,18,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fd", A(63,18,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fdiv.", A(63,18,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fd.", A(63,18,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fs", A(63,20,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fsub.", A(63,20,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fs.", A(63,20,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fadd", A(63,21,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fa", A(63,21,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, +{ "fadd.", A(63,21,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, +{ "fa.", A(63,21,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, + +{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, +{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, + +{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fre", A(63,24,0), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, +{ "fre.", A(63,24,1), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, + +{ "fmul", A(63,25,0), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, +{ "fm", A(63,25,0), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, +{ "fmul.", A(63,25,1), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, +{ "fm.", A(63,25,1), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, + +{ "frsqrte", A(63,26,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, +{ "frsqrte.",A(63,26,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, + +{ "fmsub", A(63,28,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fms", A(63,28,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fmsub.", A(63,28,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fms.", A(63,28,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fmadd", A(63,29,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fma", A(63,29,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fmadd.", A(63,29,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fma.", A(63,29,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fnmsub", A(63,30,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnms", A(63,30,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fnmsub.", A(63,30,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnms.", A(63,30,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fnmadd", A(63,31,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnma", A(63,31,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, +{ "fnmadd.", A(63,31,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, +{ "fnma.", A(63,31,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, + +{ "fcmpo", X(63,32), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, + +{ "dmulq", XRC(63,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dmulq.", XRC(63,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "drrndq", ZRC(63,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, +{ "drrndq.", ZRC(63,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "mtfsb1", XRC(63,38,0), XRARB_MASK, COM, { BT } }, +{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, COM, { BT } }, + +{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fneg.", XRC(63,40,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), COM, { BF, BFA } }, + +{ "dscliq", ZRC(63,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscliq.", ZRC(63,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "dquaiq", ZRC(63,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, +{ "dquaiq.", ZRC(63,67,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, + +{ "mtfsb0", XRC(63,70,0), XRARB_MASK, COM, { BT } }, +{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, COM, { BT } }, + +{ "fmr", XRC(63,72,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fmr.", XRC(63,72,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dscriq", ZRC(63,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, +{ "dscriq.", ZRC(63,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, + +{ "drintxq", ZRC(63,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintxq.",ZRC(63,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dcmpoq", X(63,130), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "mtfsfi", XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, +{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, + +{ "fnabs", XRC(63,136,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fnabs.", XRC(63,136,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dtstexq", X(63,162), X_MASK, POWER6, { BF, FRA, FRB } }, +{ "dtstdcq", Z(63,194), Z_MASK, POWER6, { BF, FRA, DCM } }, +{ "dtstdgq", Z(63,226), Z_MASK, POWER6, { BF, FRA, DGM } }, + +{ "drintnq", ZRC(63,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, +{ "drintnq.",ZRC(63,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, + +{ "dctqpq", XRC(63,258,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctqpq.", XRC(63,258,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "fabs", XRC(63,264,0), XRA_MASK, COM, { FRT, FRB } }, +{ "fabs.", XRC(63,264,1), XRA_MASK, COM, { FRT, FRB } }, + +{ "dctfixq", XRC(63,290,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dctfixq.",XRC(63,290,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "ddedpdq", XRC(63,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, +{ "ddedpdq.",XRC(63,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, + +{ "dxexq", XRC(63,354,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dxexq.", XRC(63,354,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "frin", XRC(63,392,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frin.", XRC(63,392,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "friz", XRC(63,424,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "friz.", XRC(63,424,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frip", XRC(63,456,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frip.", XRC(63,456,1), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frim", XRC(63,488,0), XRA_MASK, POWER5, { FRT, FRB } }, +{ "frim.", XRC(63,488,1), XRA_MASK, POWER5, { FRT, FRB } }, + +{ "dsubq", XRC(63,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "dsubq.", XRC(63,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +{ "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } }, +{ "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } }, + +{ "dcmpuq", X(63,642), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "dtstsfq", X(63,674), X_MASK, POWER6, { BF, FRA, FRB } }, + +{ "mtfsf", XFL(63,711,0), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, +{ "mtfsf.", XFL(63,711,1), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, + +{ "drdpq", XRC(63,770,0), X_MASK, POWER6, { FRT, FRB } }, +{ "drdpq.", XRC(63,770,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "dcffixq", XRC(63,802,0), X_MASK, POWER6, { FRT, FRB } }, +{ "dcffixq.",XRC(63,802,1), X_MASK, POWER6, { FRT, FRB } }, + +{ "fctid", XRC(63,814,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fctid.", XRC(63,814,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "fctidz", XRC(63,815,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "denbcdq", XRC(63,834,0), X_MASK, POWER6, { S, FRT, FRB } }, +{ "denbcdq.",XRC(63,834,1), X_MASK, POWER6, { S, FRT, FRB } }, + +{ "fcfid", XRC(63,846,0), XRA_MASK, PPC64, { FRT, FRB } }, +{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC64, { FRT, FRB } }, + +{ "diexq", XRC(63,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "diexq.", XRC(63,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, + +}; + +const int powerpc_num_opcodes = + sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); + +/* The macro table. This is only used by the assembler. */ + +/* The expressions of the form (-x ! 31) & (x | 31) have the value 0 + when x=0; 32-x when x is between 1 and 31; are negative if x is + negative; and are 32 or more otherwise. This is what you want + when, for instance, you are emulating a right shift by a + rotate-left-and-mask, because the underlying instructions support + shifts of size 0 but not shifts of size 32. By comparison, when + extracting x bits from some word you want to use just 32-x, because + the underlying instructions don't support extracting 0 bits but do + support extracting the whole word (32 bits in this case). */ + +const struct powerpc_macro powerpc_macros[] = { +{ "extldi", 4, PPC64, "rldicr %0,%1,%3,(%2)-1" }, +{ "extldi.", 4, PPC64, "rldicr. %0,%1,%3,(%2)-1" }, +{ "extrdi", 4, PPC64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, +{ "extrdi.", 4, PPC64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, +{ "insrdi", 4, PPC64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, +{ "insrdi.", 4, PPC64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, +{ "rotrdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),0" }, +{ "rotrdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" }, +{ "sldi", 3, PPC64, "rldicr %0,%1,%2,63-(%2)" }, +{ "sldi.", 3, PPC64, "rldicr. %0,%1,%2,63-(%2)" }, +{ "srdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" }, +{ "srdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" }, +{ "clrrdi", 3, PPC64, "rldicr %0,%1,0,63-(%2)" }, +{ "clrrdi.", 3, PPC64, "rldicr. %0,%1,0,63-(%2)" }, +{ "clrlsldi",4, PPC64, "rldic %0,%1,%3,(%2)-(%3)" }, +{ "clrlsldi.",4, PPC64, "rldic. %0,%1,%3,(%2)-(%3)" }, + +{ "extlwi", 4, PPCCOM, "rlwinm %0,%1,%3,0,(%2)-1" }, +{ "extlwi.", 4, PPCCOM, "rlwinm. %0,%1,%3,0,(%2)-1" }, +{ "extrwi", 4, PPCCOM, "rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, +{ "extrwi.", 4, PPCCOM, "rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, +{ "inslwi", 4, PPCCOM, "rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" }, +{ "inslwi.", 4, PPCCOM, "rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"}, +{ "insrwi", 4, PPCCOM, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, +{ "insrwi.", 4, PPCCOM, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, +{ "rotrwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" }, +{ "rotrwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" }, +{ "slwi", 3, PPCCOM, "rlwinm %0,%1,%2,0,31-(%2)" }, +{ "sli", 3, PWRCOM, "rlinm %0,%1,%2,0,31-(%2)" }, +{ "slwi.", 3, PPCCOM, "rlwinm. %0,%1,%2,0,31-(%2)" }, +{ "sli.", 3, PWRCOM, "rlinm. %0,%1,%2,0,31-(%2)" }, +{ "srwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "sri", 3, PWRCOM, "rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "srwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "sri.", 3, PWRCOM, "rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, +{ "clrrwi", 3, PPCCOM, "rlwinm %0,%1,0,0,31-(%2)" }, +{ "clrrwi.", 3, PPCCOM, "rlwinm. %0,%1,0,0,31-(%2)" }, +{ "clrlslwi",4, PPCCOM, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, +{ "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, +}; + +const int powerpc_num_macros = + sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); + + +/* This file provides several disassembler functions, all of which use + the disassembler interface defined in dis-asm.h. Several functions + are provided because this file handles disassembly for the PowerPC + in both big and little endian mode and also for the POWER (RS/6000) + chip. */ + +static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); + +/* Determine which set of machines to disassemble for. PPC403/601 or + BookE. For convenience, also disassemble instructions supported + by the AltiVec vector unit. */ + +static int +powerpc_dialect (struct disassemble_info *info) +{ + int dialect = PPC_OPCODE_PPC; + + if (BFD_DEFAULT_TARGET_SIZE == 64) + dialect |= PPC_OPCODE_64; + + if (info->disassembler_options + && strstr (info->disassembler_options, "booke") != NULL) + dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; + else if ((info->mach == bfd_mach_ppc_e500) + || (info->disassembler_options + && strstr (info->disassembler_options, "e500") != NULL)) + dialect |= (PPC_OPCODE_BOOKE + | PPC_OPCODE_SPE | PPC_OPCODE_ISEL + | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK + | PPC_OPCODE_RFMCI); + else if (info->disassembler_options + && strstr (info->disassembler_options, "efs") != NULL) + dialect |= PPC_OPCODE_EFS; + else if (info->disassembler_options + && strstr (info->disassembler_options, "e300") != NULL) + dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; + else if (info->disassembler_options + && strstr (info->disassembler_options, "440") != NULL) + dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 + | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; + else + dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC + | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); + + if (info->disassembler_options + && strstr (info->disassembler_options, "power4") != NULL) + dialect |= PPC_OPCODE_POWER4; + + if (info->disassembler_options + && strstr (info->disassembler_options, "power5") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; + + if (info->disassembler_options + && strstr (info->disassembler_options, "cell") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; + + if (info->disassembler_options + && strstr (info->disassembler_options, "power6") != NULL) + dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; + + if (info->disassembler_options + && strstr (info->disassembler_options, "any") != NULL) + dialect |= PPC_OPCODE_ANY; + + if (info->disassembler_options) + { + if (strstr (info->disassembler_options, "32") != NULL) + dialect &= ~PPC_OPCODE_64; + else if (strstr (info->disassembler_options, "64") != NULL) + dialect |= PPC_OPCODE_64; + } + + info->private_data = (char *) 0 + dialect; + return dialect; +} + +/* Qemu default */ +int +print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 1, dialect); +} + +/* Print a big endian PowerPC instruction. */ + +int +print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 1, dialect); +} + +/* Print a little endian PowerPC instruction. */ + +int +print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) +{ + int dialect = (char *) info->private_data - (char *) 0; + return print_insn_powerpc (memaddr, info, 0, dialect); +} + +/* Print a POWER (RS/6000) instruction. */ + +int +print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) +{ + return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); +} + +/* Extract the operand value from the PowerPC or POWER instruction. */ + +static long +operand_value_powerpc (const struct powerpc_operand *operand, + unsigned long insn, int dialect) +{ + long value; + int invalid; + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, dialect, &invalid); + else + { + value = (insn >> operand->shift) & operand->bitm; + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + { + /* BITM is always some number of zeros followed by some + number of ones, followed by some numer of zeros. */ + unsigned long top = operand->bitm; + /* top & -top gives the rightmost 1 bit, so this + fills in any trailing zeros. */ + top |= (top & -top) - 1; + top &= ~(top >> 1); + value = (value ^ top) - top; + } + } + + return value; +} + +/* Determine whether the optional operand(s) should be printed. */ + +static int +skip_optional_operands (const unsigned char *opindex, + unsigned long insn, int dialect) +{ + const struct powerpc_operand *operand; + + for (; *opindex != 0; opindex++) + { + operand = &powerpc_operands[*opindex]; + if ((operand->flags & PPC_OPERAND_NEXT) != 0 + || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 + && operand_value_powerpc (operand, insn, dialect) != 0)) + return 0; + } + + return 1; +} + +/* Print a PowerPC or POWER instruction. */ + +static int +print_insn_powerpc (bfd_vma memaddr, + struct disassemble_info *info, + int bigendian, + int dialect) +{ + bfd_byte buffer[4]; + int status; + unsigned long insn; + const struct powerpc_opcode *opcode; + const struct powerpc_opcode *opcode_end; + unsigned long op; + + if (dialect == 0) + dialect = powerpc_dialect (info); + + status = (*info->read_memory_func) (memaddr, buffer, 4, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + if (bigendian) + insn = bfd_getb32 (buffer); + else + insn = bfd_getl32 (buffer); + + /* Get the major opcode of the instruction. */ + op = PPC_OP (insn); + + /* Find the first match in the opcode table. We could speed this up + a bit by doing a binary search on the major opcode. */ + opcode_end = powerpc_opcodes + powerpc_num_opcodes; + again: + for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + { + unsigned long table_op; + const unsigned char *opindex; + const struct powerpc_operand *operand; + int invalid; + int need_comma; + int need_paren; + int skip_optional; + + table_op = PPC_OP (opcode->opcode); + if (op < table_op) + break; + if (op > table_op) + continue; + + if ((insn & opcode->mask) != opcode->opcode + || (opcode->flags & dialect) == 0) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + operand = powerpc_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, dialect, &invalid); + } + if (invalid) + continue; + + /* The instruction is valid. */ + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* Now extract and print the operands. */ + need_comma = 0; + need_paren = 0; + skip_optional = -1; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + long value; + + operand = powerpc_operands + *opindex; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & PPC_OPERAND_FAKE) != 0) + continue; + + /* If all of the optional operands have the value zero, + then don't print any of them. */ + if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) + { + if (skip_optional < 0) + skip_optional = skip_optional_operands (opindex, insn, + dialect); + if (skip_optional) + continue; + } + + value = operand_value_powerpc (operand, insn, dialect); + + if (need_comma) + { + (*info->fprintf_func) (info->stream, ","); + need_comma = 0; + } + + /* Print the operand as directed by the flags. */ + if ((operand->flags & PPC_OPERAND_GPR) != 0 + || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) + (*info->fprintf_func) (info->stream, "r%ld", value); + else if ((operand->flags & PPC_OPERAND_FPR) != 0) + (*info->fprintf_func) (info->stream, "f%ld", value); + else if ((operand->flags & PPC_OPERAND_VR) != 0) + (*info->fprintf_func) (info->stream, "v%ld", value); + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) + (*info->print_address_func) (memaddr + value, info); + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) + (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); + else if ((operand->flags & PPC_OPERAND_CR) == 0 + || (dialect & PPC_OPCODE_PPC) == 0) + (*info->fprintf_func) (info->stream, "%ld", value); + else + { + if (operand->bitm == 7) + (*info->fprintf_func) (info->stream, "cr%ld", value); + else + { + static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; + int cr; + int cc; + + cr = value >> 2; + if (cr != 0) + (*info->fprintf_func) (info->stream, "4*cr%d+", cr); + cc = value & 3; + (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); + } + } + + if (need_paren) + { + (*info->fprintf_func) (info->stream, ")"); + need_paren = 0; + } + + if ((operand->flags & PPC_OPERAND_PARENS) == 0) + need_comma = 1; + else + { + (*info->fprintf_func) (info->stream, "("); + need_paren = 1; + } + } + + /* We have found and printed an instruction; return. */ + return 4; + } + + if ((dialect & PPC_OPCODE_ANY) != 0) + { + dialect = ~PPC_OPCODE_ANY; + goto again; + } + + /* We could not find a match. */ + (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); + + return 4; +} diff --git a/qemu/qemu-git/ppc.ld b/qemu/qemu-git/ppc.ld new file mode 100644 index 0000000..5248ef1 --- /dev/null +++ b/qemu/qemu-git/ppc.ld @@ -0,0 +1,227 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glink) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + PROVIDE (_SDA2_BASE_ = 32768); + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .got1 : { *(.got1) } + .got2 : { *(.got2) } + .dynamic : { *(.dynamic) } + .got : SPECIAL { *(.got) } + . = DATA_SEGMENT_RELRO_END (0, .); + .plt : SPECIAL { *(.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .got : SPECIAL { *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + PROVIDE (_SDA_BASE_ = 32768); + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); + } + .plt : SPECIAL { *(.plt) } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /DISCARD/ : { *(.fixup) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/ppc64.ld b/qemu/qemu-git/ppc64.ld new file mode 100644 index 0000000..dea0dbd --- /dev/null +++ b/qemu/qemu-git/ppc64.ld @@ -0,0 +1,220 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", + "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.toc) + *(.rela.opd) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.tocbss : { *(.rela.tocbss) } + .init : + { + KEEP (*(.init)) + } =0x60000000 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.sfpr .glink) + } =0x60000000 + .fini : + { + KEEP (*(.fini)) + } =0x60000000 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Adjust the address for the data segment. We want to +adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN +(0x10000, 0x1000); /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) +*(.gcc_except_table.*) } /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } + PROVIDE (__fini_array_end = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .toc1 ALIGN(8) : { *(.toc1) } + .opd ALIGN(8) : { KEEP (*(.opd)) } + .got ALIGN(8) : { *(.got .toc) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .tocbss ALIGN(8) : { *(.tocbss)} + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/qemu-git/qemu-common.h b/qemu/qemu-git/qemu-common.h new file mode 100644 index 0000000..8630f8c --- /dev/null +++ b/qemu/qemu-git/qemu-common.h @@ -0,0 +1,275 @@ +/* Common header file that is included by all of qemu. */ +#ifndef QEMU_COMMON_H +#define QEMU_COMMON_H + +#define QEMU_NORETURN __attribute__ ((__noreturn__)) +#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT +#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define QEMU_WARN_UNUSED_RESULT +#endif + +/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that + cannot include the following headers without conflicts. This condition has + to be removed once dyngen is gone. */ +#ifndef __DYNGEN_EXEC_H__ + +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config-host.h" + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif +#if !defined(ENOTSUP) +#define ENOTSUP 4096 +#endif + +#ifndef CONFIG_IOVEC +#define CONFIG_IOVEC +struct iovec { + void *iov_base; + size_t iov_len; +}; +#else +#include +#endif + +#ifdef _WIN32 +#define fsync _commit +#define lseek _lseeki64 +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" +#endif + +/* FIXME: Remove NEED_CPU_H. */ +#ifndef NEED_CPU_H + +#include +#include "osdep.h" +#include "bswap.h" + +#else + +#include "cpu.h" + +#endif /* !defined(NEED_CPU_H) */ + +/* bottom halves */ +typedef struct QEMUBH QEMUBH; + +typedef void QEMUBHFunc(void *opaque); + +void async_context_push(void); +void async_context_pop(void); +int get_async_context_id(void); + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +void qemu_bh_schedule(QEMUBH *bh); +/* Bottom halfs that are scheduled from a bottom half handler are instantly + * invoked. This can create an infinite loop if a bottom half handler + * schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by + * ensuring that the bottom half isn't executed until the next main loop + * iteration. + */ +void qemu_bh_schedule_idle(QEMUBH *bh); +void qemu_bh_cancel(QEMUBH *bh); +void qemu_bh_delete(QEMUBH *bh); +int qemu_bh_poll(void); +void qemu_bh_update_timeout(int *timeout); + +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); + +void qemu_get_timedate(struct tm *tm, int offset); +int qemu_timedate_diff(struct tm *tm); + +/* cutils.c */ +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +int qemu_strnlen(const char *s, int max_len); +time_t mktimegm(struct tm *tm); +int qemu_fls(int i); +int qemu_fdatasync(int fd); + +/* path.c */ +void init_paths(const char *prefix); +const char *path(const char *pathname); + +#define qemu_isalnum(c) isalnum((unsigned char)(c)) +#define qemu_isalpha(c) isalpha((unsigned char)(c)) +#define qemu_iscntrl(c) iscntrl((unsigned char)(c)) +#define qemu_isdigit(c) isdigit((unsigned char)(c)) +#define qemu_isgraph(c) isgraph((unsigned char)(c)) +#define qemu_islower(c) islower((unsigned char)(c)) +#define qemu_isprint(c) isprint((unsigned char)(c)) +#define qemu_ispunct(c) ispunct((unsigned char)(c)) +#define qemu_isspace(c) isspace((unsigned char)(c)) +#define qemu_isupper(c) isupper((unsigned char)(c)) +#define qemu_isxdigit(c) isxdigit((unsigned char)(c)) +#define qemu_tolower(c) tolower((unsigned char)(c)) +#define qemu_toupper(c) toupper((unsigned char)(c)) +#define qemu_isascii(c) isascii((unsigned char)(c)) +#define qemu_toascii(c) toascii((unsigned char)(c)) + +void *qemu_malloc(size_t size); +void *qemu_realloc(void *ptr, size_t size); +void *qemu_mallocz(size_t size); +void qemu_free(void *ptr); +char *qemu_strdup(const char *str); +char *qemu_strndup(const char *str, size_t size); + +void *get_mmap_addr(unsigned long size); + + +void qemu_mutex_lock_iothread(void); +void qemu_mutex_unlock_iothread(void); + +int qemu_open(const char *name, int flags, ...); +void qemu_set_cloexec(int fd); + +#ifndef _WIN32 +int qemu_pipe(int pipefd[2]); +#endif + +/* Error handling. */ + +void QEMU_NORETURN hw_error(const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +/* IO callbacks. */ +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); +typedef void IOHandler(void *opaque); + +struct ParallelIOArg { + void *buffer; + int count; +}; + +typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); + +/* A load of opaque types so that device init declarations don't have to + pull in all the real definitions. */ +typedef struct NICInfo NICInfo; +typedef struct HCIInfo HCIInfo; +typedef struct AudioState AudioState; +typedef struct BlockDriverState BlockDriverState; +typedef struct DisplayState DisplayState; +typedef struct DisplayChangeListener DisplayChangeListener; +typedef struct DisplaySurface DisplaySurface; +typedef struct DisplayAllocator DisplayAllocator; +typedef struct PixelFormat PixelFormat; +typedef struct TextConsole TextConsole; +typedef TextConsole QEMUConsole; +typedef struct CharDriverState CharDriverState; +typedef struct MACAddr MACAddr; +typedef struct VLANState VLANState; +typedef struct VLANClientState VLANClientState; +typedef struct QEMUFile QEMUFile; +typedef struct i2c_bus i2c_bus; +typedef struct i2c_slave i2c_slave; +typedef struct SMBusDevice SMBusDevice; +typedef struct QEMUTimer QEMUTimer; +typedef struct PCIHostState PCIHostState; +typedef struct PCIExpressHost PCIExpressHost; +typedef struct PCIBus PCIBus; +typedef struct PCIDevice PCIDevice; +typedef struct SerialState SerialState; +typedef struct IRQState *qemu_irq; +typedef struct PCMCIACardState PCMCIACardState; +typedef struct MouseTransformInfo MouseTransformInfo; +typedef struct uWireSlave uWireSlave; +typedef struct I2SCodec I2SCodec; +typedef struct DeviceState DeviceState; +typedef struct SSIBus SSIBus; + +/* CPU save/load. */ +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + +/* Force QEMU to stop what it's doing and service IO */ +void qemu_service_io(void); + +/* Force QEMU to process pending events */ +void qemu_notify_event(void); + +/* Unblock cpu */ +void qemu_cpu_kick(void *env); +int qemu_cpu_self(void *env); + +#ifdef CONFIG_USER_ONLY +#define qemu_init_vcpu(env) do { } while (0) +#else +void qemu_init_vcpu(void *env); +#endif + +typedef struct QEMUIOVector { + struct iovec *iov; + int niov; + int nalloc; + size_t size; +} QEMUIOVector; + +void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); +void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); +void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); +void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size); +void qemu_iovec_destroy(QEMUIOVector *qiov); +void qemu_iovec_reset(QEMUIOVector *qiov); +void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf); +void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count); + +struct Monitor; +typedef struct Monitor Monitor; + +/* Convert a byte between binary and BCD. */ +static inline uint8_t to_bcd(uint8_t val) +{ + return ((val / 10) << 4) | (val % 10); +} + +static inline uint8_t from_bcd(uint8_t val) +{ + return ((val >> 4) * 10) + (val & 0x0f); +} + +#include "module.h" + +#endif /* dyngen-exec.h hack */ + +#endif diff --git a/qemu/qemu-git/qemu-lock.h b/qemu/qemu-git/qemu-lock.h new file mode 100644 index 0000000..9a3e6ac --- /dev/null +++ b/qemu/qemu-git/qemu-lock.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +/* Locking primitives. Most of this code should be redundant - + system emulation doesn't need/use locking, NPTL userspace uses + pthread mutexes, and non-NPTL userspace isn't threadsafe anyway. + In either case a spinlock is probably the wrong kind of lock. + Spinlocks are only good if you know annother CPU has the lock and is + likely to release it soon. In environments where you have more threads + than physical CPUs (the extreme case being a single CPU host) a spinlock + simply wastes CPU until the OS decides to preempt it. */ +#if defined(CONFIG_USE_NPTL) + +#include +#define spin_lock pthread_mutex_lock +#define spin_unlock pthread_mutex_unlock +#define spinlock_t pthread_mutex_t +#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER + +#else + +#if defined(__hppa__) + +typedef int spinlock_t[4]; + +#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 } + +static inline void resetlock (spinlock_t *p) +{ + (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1; +} + +#else + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +static inline void resetlock (spinlock_t *p) +{ + *p = SPIN_LOCK_UNLOCKED; +} + +#endif + +#if defined(_ARCH_PPC) +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + " lwarx %0,0,%1\n" + " xor. %0,%3,%0\n" + " bne $+12\n" + " stwcx. %2,0,%1\n" + " bne- $-16\n" + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#elif defined(__i386__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__x86_64__) +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; +} +#elif defined(__s390__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#elif defined(__alpha__) +static inline int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#elif defined(__sparc__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#elif defined(__arm__) +static inline int testandset (int *spinlock) +{ + register unsigned int ret; + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} +#elif defined(__mc68000) +static inline int testandset (int *p) +{ + char ret; + __asm__ __volatile__("tas %1; sne %0" + : "=r" (ret) + : "m" (p) + : "cc","memory"); + return ret; +} +#elif defined(__hppa__) + +/* Because malloc only guarantees 8-byte alignment for malloc'd data, + and GCC only guarantees 8-byte alignment for stack locals, we can't + be assured of 16-byte alignment for atomic lock data even if we + specify "__attribute ((aligned(16)))" in the type declaration. So, + we use a struct containing an array of four ints for the atomic lock + type and dynamically select the 16-byte aligned int from the array + for the semaphore. */ +#define __PA_LDCW_ALIGNMENT 16 +static inline void *ldcw_align (void *p) { + unsigned long a = (unsigned long)p; + a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); + return (void *)a; +} + +static inline int testandset (spinlock_t *p) +{ + unsigned int ret; + p = ldcw_align(p); + __asm__ __volatile__("ldcw 0(%1),%0" + : "=r" (ret) + : "r" (p) + : "memory" ); + return !ret; +} + +#elif defined(__ia64) + +#include + +static inline int testandset (int *p) +{ + return __sync_lock_test_and_set (p, 1); +} +#elif defined(__mips__) +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ( + " .set push \n" + " .set noat \n" + " .set mips2 \n" + "1: li $1, 1 \n" + " ll %0, %1 \n" + " sc $1, %1 \n" + " beqz $1, 1b \n" + " .set pop " + : "=r" (ret), "+R" (*p) + : + : "memory"); + + return ret; +} +#else +#error unimplemented CPU support +#endif + +#if defined(CONFIG_USER_ONLY) +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + resetlock(lock); +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} +#else +static inline void spin_lock(spinlock_t *lock) +{ +} + +static inline void spin_unlock(spinlock_t *lock) +{ +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return 1; +} +#endif + +#endif diff --git a/qemu/qemu-git/qemu-log.h b/qemu/qemu-git/qemu-log.h new file mode 100644 index 0000000..fccfb11 --- /dev/null +++ b/qemu/qemu-git/qemu-log.h @@ -0,0 +1,93 @@ +#ifndef QEMU_LOG_H +#define QEMU_LOG_H + +/* The deprecated global variables: */ +extern FILE *logfile; +extern int loglevel; + + +/* + * The new API: + * + */ + +/* Log settings checking macros: */ + +/* Returns true if qemu_log() will really write somewhere + */ +#define qemu_log_enabled() (logfile != NULL) + +/* Returns true if a bit is set in the current loglevel mask + */ +#define qemu_loglevel_mask(b) ((loglevel & (b)) != 0) + + +/* Logging functions: */ + +/* main logging function + */ +#define qemu_log(...) do { \ + if (logfile) \ + fprintf(logfile, ## __VA_ARGS__); \ + } while (0) + +/* vfprintf-like logging function + */ +#define qemu_log_vprintf(fmt, va) do { \ + if (logfile) \ + vfprintf(logfile, fmt, va); \ + } while (0) + +/* log only if a bit is set on the current loglevel mask + */ +#define qemu_log_mask(b, ...) do { \ + if (loglevel & (b)) \ + fprintf(logfile, ## __VA_ARGS__); \ + } while (0) + + + + +/* Special cases: */ + +/* cpu_dump_state() logging functions: */ +#define log_cpu_state(env, f) cpu_dump_state((env), logfile, fprintf, (f)); +#define log_cpu_state_mask(b, env, f) do { \ + if (loglevel & (b)) log_cpu_state((env), (f)); \ + } while (0) + +/* disas() and target_disas() to logfile: */ +#define log_target_disas(start, len, flags) \ + target_disas(logfile, (start), (len), (flags)) +#define log_disas(start, len) \ + disas(logfile, (start), (len)) + +/* page_dump() output to the log file: */ +#define log_page_dump() page_dump(logfile) + + + +/* Maintenance: */ + +/* fflush() the log file */ +#define qemu_log_flush() fflush(logfile) + +/* Close the log file */ +#define qemu_log_close() do { \ + fclose(logfile); \ + logfile = NULL; \ + } while (0) + +/* Set up a new log file */ +#define qemu_log_set_file(f) do { \ + logfile = (f); \ + } while (0) + +/* Set up a new log file, only if none is set */ +#define qemu_log_try_set_file(f) do { \ + if (!logfile) \ + logfile = (f); \ + } while (0) + + +#endif diff --git a/qemu/qemu-git/qemu-malloc.c b/qemu/qemu-git/qemu-malloc.c new file mode 100644 index 0000000..5d9e34d --- /dev/null +++ b/qemu/qemu-git/qemu-malloc.c @@ -0,0 +1,102 @@ +/* + * malloc-like functions for system emulation. + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include + +static void *oom_check(void *ptr) +{ + if (ptr == NULL) { + abort(); + } + return ptr; +} + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +static int allow_zero_malloc(void) +{ +#if defined(CONFIG_ZERO_MALLOC) + return 1; +#else + return 0; +#endif +} + +void *qemu_malloc(size_t size) +{ + if (!size && !allow_zero_malloc()) { + abort(); + } + return oom_check(malloc(size ? size : 1)); +} + +void *qemu_realloc(void *ptr, size_t size) +{ + if (size) { + return oom_check(realloc(ptr, size)); + } else if (allow_zero_malloc()) { + return oom_check(realloc(ptr, size ? size : 1)); + } + abort(); +} + +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + memset(ptr, 0, size); + return ptr; +} + +char *qemu_strdup(const char *str) +{ + char *ptr; + size_t len = strlen(str); + ptr = qemu_malloc(len + 1); + memcpy(ptr, str, len + 1); + return ptr; +} + +char *qemu_strndup(const char *str, size_t size) +{ + const char *end = memchr(str, 0, size); + char *new; + + if (end) { + size = end - str; + } + + new = qemu_malloc(size + 1); + new[size] = 0; + + return memcpy(new, str, size); +} diff --git a/qemu/qemu-git/qemu-queue.h b/qemu/qemu-git/qemu-queue.h new file mode 100644 index 0000000..1d07745 --- /dev/null +++ b/qemu/qemu-git/qemu-queue.h @@ -0,0 +1,449 @@ +/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */ + +/* + * Qemu version: Copy from netbsd, removed debug code, removed some of + * the implementations. Left in lists, simple queues, tail queues and + * circular queues. + */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef QEMU_SYS_QUEUE_H_ +#define QEMU_SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: + * lists, simple queues, tail queues, and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define QLIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define QLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define QLIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define QLIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define QLIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define QLIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +#define QLIST_FOREACH_SAFE(var, head, field, next_var) \ + for ((var) = ((head)->lh_first); \ + (var) && ((next_var) = ((var)->field.le_next), 1); \ + (var) = (next_var)) + +/* + * List access methods. + */ +#define QLIST_EMPTY(head) ((head)->lh_first == NULL) +#define QLIST_FIRST(head) ((head)->lh_first) +#define QLIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Simple queue definitions. + */ +#define QSIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define QSIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define QSIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define QSIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + QSIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->sqh_first); \ + (var) && ((next = ((var)->field.sqe_next)), 1); \ + (var) = (next)) + +#define QSIMPLEQ_CONCAT(head1, head2) do { \ + if (!QSIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + QSIMPLEQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_LAST(head, type, field) \ + (QSIMPLEQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->sqh_last) - offsetof(struct type, field)))) + +/* + * Simple queue access methods. + */ +#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define QSIMPLEQ_FIRST(head) ((head)->sqh_first) +#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define Q_TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,) + +#define QTAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define Q_TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define QTAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define QTAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \ + for ((var) = ((head)->tqh_first); \ + (var) && ((next_var) = ((var)->field.tqe_next), 1); \ + (var) = (next_var)) + +#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define QTAILQ_FIRST(head) ((head)->tqh_first) +#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define QTAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define QTAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define QCIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define QCIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define QCIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define QCIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define QCIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define QCIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define QCIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define QCIRCLEQ_FIRST(head) ((head)->cqh_first) +#define QCIRCLEQ_LAST(head) ((head)->cqh_last) +#define QCIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define QCIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define QCIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define QCIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* !QEMU_SYS_QUEUE_H_ */ diff --git a/qemu/qemu-git/rules.mak b/qemu/qemu-git/rules.mak new file mode 100644 index 0000000..5941b73 --- /dev/null +++ b/qemu/qemu-git/rules.mak @@ -0,0 +1,55 @@ + +# Don't use implicit rules or variables +# we have explicit rules for everything +MAKEFLAGS += -rR + +# Files with this suffixes are final, don't try to generate them +# using implicit rules +%.d: +%.h: +%.c: +%.m: +%.mak: + +# Flags for dependency generation +QEMU_DGFLAGS += -MMD -MP -MT $@ + +%.o: %.c + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@") + +%.o: %.S + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@") + +%.o: %.m + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") + +LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS)," LINK $(TARGET_DIR)$@") + +%$(EXESUF): %.o + $(call LINK,$^) + +%.a: + $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@") + +quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) + +# cc-option +# Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) + +cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ + >/dev/null 2>&1 && echo OK), $2, $3) + +VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi +set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES), $(eval vpath $(PATTERN) $1))) + +# Generate timestamp files for .h include files + +%.h: %.h-timestamp + @test -f $@ || cp $< $@ + +%.h-timestamp: %.mak + $(call quiet-command, sh $(SRC_PATH)/create_config < $< > $@, " GEN $*.h") + @cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h + +# will delete the target of a rule if commands exit with a nonzero exit status +.DELETE_ON_ERROR: diff --git a/qemu/qemu-git/s390-dis.c b/qemu/qemu-git/s390-dis.c new file mode 100644 index 0000000..86dd84f --- /dev/null +++ b/qemu/qemu-git/s390-dis.c @@ -0,0 +1,1704 @@ +/* s390-dis.c -- Disassemble S390 instructions + Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of GDB, GAS and the GNU binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include +#include "dis-asm.h" + +/* s390.h -- Header file for S390 opcode table + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef S390_H +#define S390_H + +/* List of instruction sets variations. */ + +enum s390_opcode_mode_val + { + S390_OPCODE_ESA = 0, + S390_OPCODE_ZARCH + }; + +enum s390_opcode_cpu_val + { + S390_OPCODE_G5 = 0, + S390_OPCODE_G6, + S390_OPCODE_Z900, + S390_OPCODE_Z990, + S390_OPCODE_Z9_109, + S390_OPCODE_Z9_EC + }; + +/* The opcode table is an array of struct s390_opcode. */ + +struct s390_opcode + { + /* The opcode name. */ + const char * name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned char opcode[6]; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned char mask[6]; + + /* The opcode length in bytes. */ + int oplen; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[6]; + + /* Bitmask of execution modes this opcode is available for. */ + unsigned int modes; + + /* First cpu this opcode is available for. */ + enum s390_opcode_cpu_val min_cpu; + }; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct s390_opcode s390_opcodes[]; +extern const int s390_num_opcodes; + +/* A opcode format table for the .insn pseudo mnemonic. */ +extern const struct s390_opcode s390_opformats[]; +extern const int s390_num_opformats; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* The operands table is an array of struct s390_operand. */ + +struct s390_operand + { + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* One bit syntax flags. */ + unsigned long flags; + }; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct s390_operand s390_operands[]; + +/* Values defined for the flags field of a struct s390_operand. */ + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define S390_OPERAND_GPR 0x1 + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define S390_OPERAND_FPR 0x2 + +/* This operand names an access register. The disassembler + prints these with a leading 'a'. */ +#define S390_OPERAND_AR 0x4 + +/* This operand names a control register. The disassembler + prints these with a leading 'c'. */ +#define S390_OPERAND_CR 0x8 + +/* This operand is a displacement. */ +#define S390_OPERAND_DISP 0x10 + +/* This operand names a base register. */ +#define S390_OPERAND_BASE 0x20 + +/* This operand names an index register, it can be skipped. */ +#define S390_OPERAND_INDEX 0x40 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define S390_OPERAND_PCREL 0x80 + +/* This operand takes signed values. */ +#define S390_OPERAND_SIGNED 0x100 + +/* This operand is a length. */ +#define S390_OPERAND_LENGTH 0x200 + +/* This operand is optional. Only a single operand at the end of + the instruction may be optional. */ +#define S390_OPERAND_OPTIONAL 0x400 + + #endif /* S390_H */ + + +static int init_flag = 0; +static int opc_index[256]; +static int current_arch_mask = 0; + +/* Set up index table for first opcode byte. */ + +static void +init_disasm (struct disassemble_info *info) +{ + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + + memset (opc_index, 0, sizeof (opc_index)); + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes; opcode < opcode_end; opcode++) + { + opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes; + while ((opcode < opcode_end) && + (opcode[1].opcode[0] == opcode->opcode[0])) + opcode++; + } +// switch (info->mach) +// { +// case bfd_mach_s390_31: + current_arch_mask = 1 << S390_OPCODE_ESA; +// break; +// case bfd_mach_s390_64: +// current_arch_mask = 1 << S390_OPCODE_ZARCH; +// break; +// default: +// abort (); +// } + init_flag = 1; +} + +/* Extracts an operand value from an instruction. */ + +static inline unsigned int +s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) +{ + unsigned int val; + int bits; + + /* Extract fragments of the operand byte for byte. */ + insn += operand->shift / 8; + bits = (operand->shift & 7) + operand->bits; + val = 0; + do + { + val <<= 8; + val |= (unsigned int) *insn++; + bits -= 8; + } + while (bits > 0); + val >>= -bits; + val &= ((1U << (operand->bits - 1)) << 1) - 1; + + /* Check for special long displacement case. */ + if (operand->bits == 20 && operand->shift == 20) + val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; + + /* Sign extend value if the operand is signed or pc relative. */ + if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) + && (val & (1U << (operand->bits - 1)))) + val |= (-1U << (operand->bits - 1)) << 1; + + /* Double value if the operand is pc relative. */ + if (operand->flags & S390_OPERAND_PCREL) + val <<= 1; + + /* Length x in an instructions has real length x + 1. */ + if (operand->flags & S390_OPERAND_LENGTH) + val++; + return val; +} + +/* Print a S390 instruction. */ + +int +print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) +{ + bfd_byte buffer[6]; + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + unsigned int value; + int status, opsize, bufsize; + char separator; + + if (init_flag == 0) + init_disasm (info); + + /* The output looks better if we put 6 bytes on a line. */ + info->bytes_per_line = 6; + + /* Every S390 instruction is max 6 bytes long. */ + memset (buffer, 0, 6); + status = (*info->read_memory_func) (memaddr, buffer, 6, info); + if (status != 0) + { + for (bufsize = 0; bufsize < 6; bufsize++) + if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) + break; + if (bufsize <= 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + /* Opsize calculation looks strange but it works + 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, + 11xxxxxx -> 6 bytes. */ + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + status = opsize > bufsize; + } + else + { + bufsize = 6; + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + } + + if (status == 0) + { + /* Find the first match in the opcode table. */ + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; + (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); + opcode++) + { + const struct s390_operand *operand; + const unsigned char *opindex; + + /* Check architecture. */ + if (!(opcode->modes & current_arch_mask)) + continue; + /* Check signature of the opcode. */ + if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] + || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] + || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] + || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] + || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) + continue; + + /* The instruction is valid. */ + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "%s\t", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* Extract the operands. */ + separator = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + unsigned int value; + + operand = s390_operands + *opindex; + value = s390_extract_operand (buffer, operand); + + if ((operand->flags & S390_OPERAND_INDEX) && value == 0) + continue; + if ((operand->flags & S390_OPERAND_BASE) && + value == 0 && separator == '(') + { + separator = ','; + continue; + } + + if (separator) + (*info->fprintf_func) (info->stream, "%c", separator); + + if (operand->flags & S390_OPERAND_GPR) + (*info->fprintf_func) (info->stream, "%%r%i", value); + else if (operand->flags & S390_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%%f%i", value); + else if (operand->flags & S390_OPERAND_AR) + (*info->fprintf_func) (info->stream, "%%a%i", value); + else if (operand->flags & S390_OPERAND_CR) + (*info->fprintf_func) (info->stream, "%%c%i", value); + else if (operand->flags & S390_OPERAND_PCREL) + (*info->print_address_func) (memaddr + (int) value, info); + else if (operand->flags & S390_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%i", (int) value); + else + (*info->fprintf_func) (info->stream, "%u", value); + + if (operand->flags & S390_OPERAND_DISP) + { + separator = '('; + } + else if (operand->flags & S390_OPERAND_BASE) + { + (*info->fprintf_func) (info->stream, ")"); + separator = ','; + } + else + separator = ','; + } + + /* Found instruction, printed it, return its size. */ + return opsize; + } + /* No matching instruction found, fall through to hex print. */ + } + + if (bufsize >= 4) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + value = (value << 8) + (unsigned int) buffer[2]; + value = (value << 8) + (unsigned int) buffer[3]; + (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); + return 4; + } + else if (bufsize >= 2) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); + return 2; + } + else + { + value = (unsigned int) buffer[0]; + (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); + return 1; + } +} +/* s390-opc.c -- S390 opcode list + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of GDB, GAS, and the GNU binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include + +/* This file holds the S390 opcode table. The opcode table + includes almost all of the extended instruction mnemonics. This + permits the disassembler to use them, and simplifies the assembler + logic, at the cost of increasing the table size. The table is + strictly constant data, so the compiler should be able to put it in + the .text section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* The operands table. + The fields are bits, shift, insert, extract, flags. */ + +const struct s390_operand s390_operands[] = +{ +#define UNUSED 0 + { 0, 0, 0 }, /* Indicates the end of the operand list */ + +#define R_8 1 /* GPR starting at position 8 */ + { 4, 8, S390_OPERAND_GPR }, +#define R_12 2 /* GPR starting at position 12 */ + { 4, 12, S390_OPERAND_GPR }, +#define R_16 3 /* GPR starting at position 16 */ + { 4, 16, S390_OPERAND_GPR }, +#define R_20 4 /* GPR starting at position 20 */ + { 4, 20, S390_OPERAND_GPR }, +#define R_24 5 /* GPR starting at position 24 */ + { 4, 24, S390_OPERAND_GPR }, +#define R_28 6 /* GPR starting at position 28 */ + { 4, 28, S390_OPERAND_GPR }, +#define R_32 7 /* GPR starting at position 32 */ + { 4, 32, S390_OPERAND_GPR }, + +#define F_8 8 /* FPR starting at position 8 */ + { 4, 8, S390_OPERAND_FPR }, +#define F_12 9 /* FPR starting at position 12 */ + { 4, 12, S390_OPERAND_FPR }, +#define F_16 10 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_20 11 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_24 12 /* FPR starting at position 24 */ + { 4, 24, S390_OPERAND_FPR }, +#define F_28 13 /* FPR starting at position 28 */ + { 4, 28, S390_OPERAND_FPR }, +#define F_32 14 /* FPR starting at position 32 */ + { 4, 32, S390_OPERAND_FPR }, + +#define A_8 15 /* Access reg. starting at position 8 */ + { 4, 8, S390_OPERAND_AR }, +#define A_12 16 /* Access reg. starting at position 12 */ + { 4, 12, S390_OPERAND_AR }, +#define A_24 17 /* Access reg. starting at position 24 */ + { 4, 24, S390_OPERAND_AR }, +#define A_28 18 /* Access reg. starting at position 28 */ + { 4, 28, S390_OPERAND_AR }, + +#define C_8 19 /* Control reg. starting at position 8 */ + { 4, 8, S390_OPERAND_CR }, +#define C_12 20 /* Control reg. starting at position 12 */ + { 4, 12, S390_OPERAND_CR }, + +#define B_16 21 /* Base register starting at position 16 */ + { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR }, +#define B_32 22 /* Base register starting at position 32 */ + { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR }, + +#define X_12 23 /* Index register starting at position 12 */ + { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR }, + +#define D_20 24 /* Displacement starting at position 20 */ + { 12, 20, S390_OPERAND_DISP }, +#define D_36 25 /* Displacement starting at position 36 */ + { 12, 36, S390_OPERAND_DISP }, +#define D20_20 26 /* 20 bit displacement starting at 20 */ + { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED }, + +#define L4_8 27 /* 4 bit length starting at position 8 */ + { 4, 8, S390_OPERAND_LENGTH }, +#define L4_12 28 /* 4 bit length starting at position 12 */ + { 4, 12, S390_OPERAND_LENGTH }, +#define L8_8 29 /* 8 bit length starting at position 8 */ + { 8, 8, S390_OPERAND_LENGTH }, + +#define U4_8 30 /* 4 bit unsigned value starting at 8 */ + { 4, 8, 0 }, +#define U4_12 31 /* 4 bit unsigned value starting at 12 */ + { 4, 12, 0 }, +#define U4_16 32 /* 4 bit unsigned value starting at 16 */ + { 4, 16, 0 }, +#define U4_20 33 /* 4 bit unsigned value starting at 20 */ + { 4, 20, 0 }, +#define U8_8 34 /* 8 bit unsigned value starting at 8 */ + { 8, 8, 0 }, +#define U8_16 35 /* 8 bit unsigned value starting at 16 */ + { 8, 16, 0 }, +#define I16_16 36 /* 16 bit signed value starting at 16 */ + { 16, 16, S390_OPERAND_SIGNED }, +#define U16_16 37 /* 16 bit unsigned value starting at 16 */ + { 16, 16, 0 }, +#define J16_16 38 /* PC relative jump offset at 16 */ + { 16, 16, S390_OPERAND_PCREL }, +#define J32_16 39 /* PC relative long offset at 16 */ + { 32, 16, S390_OPERAND_PCREL }, +#define I32_16 40 /* 32 bit signed value starting at 16 */ + { 32, 16, S390_OPERAND_SIGNED }, +#define U32_16 41 /* 32 bit unsigned value starting at 16 */ + { 32, 16, 0 }, +#define M_16 42 /* 4 bit optional mask starting at 16 */ + { 4, 16, S390_OPERAND_OPTIONAL }, +#define RO_28 43 /* optional GPR starting at position 28 */ + { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) } + +}; + + +/* Macros used to form opcodes. */ + +/* 8/16/48 bit opcodes. */ +#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 } +#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \ + (x >> 16) & 255, (x >> 8) & 255, x & 255} + +/* The new format of the INSTR_x_y and MASK_x_y defines is based + on the following rules: + 1) the middle part of the definition (x in INSTR_x_y) is the official + names of the instruction format that you can find in the principals + of operation. + 2) the last part of the definition (y in INSTR_x_y) gives you an idea + which operands the binary represenation of the instruction has. + The meanings of the letters in y are: + a - access register + c - control register + d - displacement, 12 bit + f - floating pointer register + i - signed integer, 4, 8, 16 or 32 bit + l - length, 4 or 8 bit + p - pc relative + r - general purpose register + u - unsigned integer, 4, 8, 16 or 32 bit + m - mode field, 4 bit + 0 - operand skipped. + The order of the letters reflects the layout of the format in + storage and not the order of the paramaters of the instructions. + The use of the letters is not a 100% match with the PoP but it is + quite close. + + For example the instruction "mvo" is defined in the PoP as follows: + + MVO D1(L1,B1),D2(L2,B2) [SS] + + -------------------------------------- + | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 | + -------------------------------------- + 0 8 12 16 20 32 36 + + The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD. */ + +#define INSTR_E 2, { 0,0,0,0,0,0 } /* e.g. pr */ +#define INSTR_RIE_RRP 6, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxhg */ +#define INSTR_RIL_0P 6, { J32_16,0,0,0,0 } /* e.g. jg */ +#define INSTR_RIL_RP 6, { R_8,J32_16,0,0,0,0 } /* e.g. brasl */ +#define INSTR_RIL_UP 6, { U4_8,J32_16,0,0,0,0 } /* e.g. brcl */ +#define INSTR_RIL_RI 6, { R_8,I32_16,0,0,0,0 } /* e.g. afi */ +#define INSTR_RIL_RU 6, { R_8,U32_16,0,0,0,0 } /* e.g. alfi */ +#define INSTR_RI_0P 4, { J16_16,0,0,0,0,0 } /* e.g. j */ +#define INSTR_RI_RI 4, { R_8,I16_16,0,0,0,0 } /* e.g. ahi */ +#define INSTR_RI_RP 4, { R_8,J16_16,0,0,0,0 } /* e.g. brct */ +#define INSTR_RI_RU 4, { R_8,U16_16,0,0,0,0 } /* e.g. tml */ +#define INSTR_RI_UP 4, { U4_8,J16_16,0,0,0,0 } /* e.g. brc */ +#define INSTR_RRE_00 4, { 0,0,0,0,0,0 } /* e.g. palb */ +#define INSTR_RRE_0R 4, { R_28,0,0,0,0,0 } /* e.g. tb */ +#define INSTR_RRE_AA 4, { A_24,A_28,0,0,0,0 } /* e.g. cpya */ +#define INSTR_RRE_AR 4, { A_24,R_28,0,0,0,0 } /* e.g. sar */ +#define INSTR_RRE_F0 4, { F_24,0,0,0,0,0 } /* e.g. sqer */ +#define INSTR_RRE_FF 4, { F_24,F_28,0,0,0,0 } /* e.g. debr */ +#define INSTR_RRE_R0 4, { R_24,0,0,0,0,0 } /* e.g. ipm */ +#define INSTR_RRE_RA 4, { R_24,A_28,0,0,0,0 } /* e.g. ear */ +#define INSTR_RRE_RF 4, { R_24,F_28,0,0,0,0 } /* e.g. cefbr */ +#define INSTR_RRE_RR 4, { R_24,R_28,0,0,0,0 } /* e.g. lura */ +#define INSTR_RRE_FR 4, { F_24,R_28,0,0,0,0 } /* e.g. ldgr */ +/* Actually efpc and sfpc do not take an optional operand. + This is just a workaround for existing code e.g. glibc. */ +#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ +#define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ +#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +#define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ +#define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ +#define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ +#define INSTR_RRF_R0RR 4, { R_24,R_28,R_16,0,0,0 } /* e.g. idte */ +#define INSTR_RRF_U0FF 4, { F_24,U4_16,F_28,0,0,0 } /* e.g. fixr */ +#define INSTR_RRF_U0RF 4, { R_24,U4_16,F_28,0,0,0 } /* e.g. cfebr */ +#define INSTR_RRF_UUFF 4, { F_24,U4_16,F_28,U4_20,0,0 } /* e.g. fidtr */ +#define INSTR_RRF_0UFF 4, { F_24,F_28,U4_20,0,0,0 } /* e.g. ldetr */ +#define INSTR_RRF_FFFU 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. qadtr */ +#define INSTR_RRF_M0RR 4, { R_24,R_28,M_16,0,0,0 } /* e.g. sske */ +#define INSTR_RR_0R 2, { R_12, 0,0,0,0,0 } /* e.g. br */ +#define INSTR_RR_FF 2, { F_8,F_12,0,0,0,0 } /* e.g. adr */ +#define INSTR_RR_R0 2, { R_8, 0,0,0,0,0 } /* e.g. spm */ +#define INSTR_RR_RR 2, { R_8,R_12,0,0,0,0 } /* e.g. lr */ +#define INSTR_RR_U0 2, { U8_8, 0,0,0,0,0 } /* e.g. svc */ +#define INSTR_RR_UR 2, { U4_8,R_12,0,0,0,0 } /* e.g. bcr */ +#define INSTR_RRR_F0FF 4, { F_24,F_28,F_16,0,0,0 } /* e.g. ddtr */ +#define INSTR_RSE_RRRD 6, { R_8,R_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_CCRD 6, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_RURD 6, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSL_R0RD 6, { R_8,D_20,B_16,0,0,0 } /* e.g. tp */ +#define INSTR_RSI_RRP 4, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxh */ +#define INSTR_RSY_RRRD 6, { R_8,R_12,D20_20,B_16,0,0 } /* e.g. stmy */ +#define INSTR_RSY_RURD 6, { R_8,U4_12,D20_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSY_AARD 6, { A_8,A_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RSY_CCRD 6, { C_8,C_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RS_AARD 4, { A_8,A_12,D_20,B_16,0,0 } /* e.g. lam */ +#define INSTR_RS_CCRD 4, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lctl */ +#define INSTR_RS_R0RD 4, { R_8,D_20,B_16,0,0,0 } /* e.g. sll */ +#define INSTR_RS_RRRD 4, { R_8,R_12,D_20,B_16,0,0 } /* e.g. cs */ +#define INSTR_RS_RURD 4, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icm */ +#define INSTR_RXE_FRRD 6, { F_8,D_20,X_12,B_16,0,0 } /* e.g. axbr */ +#define INSTR_RXE_RRRD 6, { R_8,D_20,X_12,B_16,0,0 } /* e.g. lg */ +#define INSTR_RXF_FRRDF 6, { F_32,F_8,D_20,X_12,B_16,0 } /* e.g. madb */ +#define INSTR_RXF_RRRDR 6, { R_32,R_8,D_20,X_12,B_16,0 } /* e.g. .insn */ +#define INSTR_RXY_RRRD 6, { R_8,D20_20,X_12,B_16,0,0 } /* e.g. ly */ +#define INSTR_RXY_FRRD 6, { F_8,D20_20,X_12,B_16,0,0 } /* e.g. ley */ +#define INSTR_RX_0RRD 4, { D_20,X_12,B_16,0,0,0 } /* e.g. be */ +#define INSTR_RX_FRRD 4, { F_8,D_20,X_12,B_16,0,0 } /* e.g. ae */ +#define INSTR_RX_RRRD 4, { R_8,D_20,X_12,B_16,0,0 } /* e.g. l */ +#define INSTR_RX_URRD 4, { U4_8,D_20,X_12,B_16,0,0 } /* e.g. bc */ +#define INSTR_SI_URD 4, { D_20,B_16,U8_8,0,0,0 } /* e.g. cli */ +#define INSTR_SIY_URD 6, { D20_20,B_16,U8_8,0,0,0 } /* e.g. tmy */ +#define INSTR_SSE_RDRD 6, { D_20,B_16,D_36,B_32,0,0 } /* e.g. mvsdk */ +#define INSTR_SS_L0RDRD 6, { D_20,L8_8,B_16,D_36,B_32,0 } /* e.g. mvc */ +#define INSTR_SS_L2RDRD 6, { D_20,B_16,D_36,L8_8,B_32,0 } /* e.g. pka */ +#define INSTR_SS_LIRDRD 6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp */ +#define INSTR_SS_LLRDRD 6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack */ +#define INSTR_SS_RRRDRD 6, { D_20,R_8,B_16,D_36,B_32,R_12 } /* e.g. mvck */ +#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 } /* e.g. plo */ +#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 } /* e.g. lmd */ +#define INSTR_S_00 4, { 0,0,0,0,0,0 } /* e.g. hsch */ +#define INSTR_S_RD 4, { D_20,B_16,0,0,0,0 } /* e.g. lpsw */ +#define INSTR_SSF_RRDRD 6, { D_20,B_16,D_36,B_32,R_8,0 } /* e.g. mvcos */ + +#define MASK_E { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIE_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RIL_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRE_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_RRE_0R { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } +#define MASK_RRE_AA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_AR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_F0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_FF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_R0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_RA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_FR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR_OPT { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF2 { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_FUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_RURR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_R0RR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0RF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_UUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_0UFF { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } +#define MASK_RRF_FFFU { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_M0RR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RR_0R { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_FF { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_R0 { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_RR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_U0 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_UR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRR_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RSE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSL_R0RD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSI_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_R0RD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RSY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_FRRDF { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_RRRDR { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RX_0RRD { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SI_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SIY_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_SSE_RDRD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L0RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L2RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LIRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LLRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD2 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD3 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_S_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_S_RD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } + +/* The opcode formats table (blueprints for .insn pseudo mnemonic). */ + +const struct s390_opcode s390_opformats[] = + { + { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 }, + { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 }, + { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0 }, + { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0 }, + { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0 }, + { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0 }, + { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0 }, + { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0 }, + { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0 }, + { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0 }, + { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0 }, + { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3 }, + { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0 }, + { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0 }, + { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR,3, 0 }, + { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3 }, + { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0 }, + { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0 }, + { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3 }, + { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD,3, 0 }, + { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0 }, + { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 }, +}; + +const int s390_num_opformats = + sizeof (s390_opformats) / sizeof (s390_opformats[0]); + +/* The opcode table. This file was generated by s390-mkopc. + + The format of the opcode table is: + + NAME OPCODE MASK OPERANDS + + Name is the name of the instruction. + OPCODE is the instruction opcode. + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + OPERANDS is the list of operands. + + The disassembler reads the table in order and prints the first + instruction which matches. */ + +const struct s390_opcode s390_opcodes[] = + { + { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0}, + { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2}, + { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0}, + { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, + { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0}, + { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, + { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, + { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, + { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2}, + { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4}, + { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2}, + { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3}, + { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3}, + { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5}, + { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5}, + { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2}, + { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2}, + { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0}, + { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0}, + { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0}, + { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0}, + { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2}, + { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0}, + { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0}, + { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0}, + { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0}, + { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0}, + { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0}, + { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2}, + { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2}, + { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2}, + { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2}, + { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5}, + { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, + { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, + { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0} +}; + +const int s390_num_opcodes = + sizeof (s390_opcodes) / sizeof (s390_opcodes[0]); diff --git a/qemu/qemu-git/s390.ld b/qemu/qemu-git/s390.ld new file mode 100644 index 0000000..a9c5370 --- /dev/null +++ b/qemu/qemu-git/s390.ld @@ -0,0 +1,201 @@ +OUTPUT_FORMAT("elf32-s390", "elf32-s390", + "elf32-s390") +OUTPUT_ARCH(s390:31-bit) +ENTRY(_start) +/* __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x07070707 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x07070707 + .fini : + { + KEEP (*(.fini)) + } =0x07070707 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/qemu/qemu-git/sh4-dis.c b/qemu/qemu-git/sh4-dis.c new file mode 100644 index 0000000..41fd866 --- /dev/null +++ b/qemu/qemu-git/sh4-dis.c @@ -0,0 +1,2083 @@ +/* Disassemble SH instructions. + Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include +#include "dis-asm.h" + +#define DEFINE_TABLE + +typedef enum + { + HEX_0, + HEX_1, + HEX_2, + HEX_3, + HEX_4, + HEX_5, + HEX_6, + HEX_7, + HEX_8, + HEX_9, + HEX_A, + HEX_B, + HEX_C, + HEX_D, + HEX_E, + HEX_F, + HEX_XX00, + HEX_00YY, + REG_N, + REG_N_D, /* nnn0 */ + REG_N_B01, /* nn01 */ + REG_M, + SDT_REG_N, + REG_NM, + REG_B, + BRANCH_12, + BRANCH_8, + IMM0_4, + IMM0_4BY2, + IMM0_4BY4, + IMM1_4, + IMM1_4BY2, + IMM1_4BY4, + PCRELIMM_8BY2, + PCRELIMM_8BY4, + IMM0_8, + IMM0_8BY2, + IMM0_8BY4, + IMM1_8, + IMM1_8BY2, + IMM1_8BY4, + PPI, + NOPX, + NOPY, + MOVX, + MOVY, + MOVX_NOPY, + MOVY_NOPX, + PSH, + PMUL, + PPI3, + PPI3NC, + PDC, + PPIC, + REPEAT, + IMM0_3c, /* xxxx 0iii */ + IMM0_3s, /* xxxx 1iii */ + IMM0_3Uc, /* 0iii xxxx */ + IMM0_3Us, /* 1iii xxxx */ + IMM0_20_4, + IMM0_20, /* follows IMM0_20_4 */ + IMM0_20BY8, /* follows IMM0_20_4 */ + DISP0_12, + DISP0_12BY2, + DISP0_12BY4, + DISP0_12BY8, + DISP1_12, + DISP1_12BY2, + DISP1_12BY4, + DISP1_12BY8 + } +sh_nibble_type; + +typedef enum + { + A_END, + A_BDISP12, + A_BDISP8, + A_DEC_M, + A_DEC_N, + A_DISP_GBR, + A_PC, + A_DISP_PC, + A_DISP_PC_ABS, + A_DISP_REG_M, + A_DISP_REG_N, + A_GBR, + A_IMM, + A_INC_M, + A_INC_N, + A_IND_M, + A_IND_N, + A_IND_R0_REG_M, + A_IND_R0_REG_N, + A_MACH, + A_MACL, + A_PR, + A_R0, + A_R0_GBR, + A_REG_M, + A_REG_N, + A_REG_B, + A_SR, + A_VBR, + A_TBR, + A_DISP_TBR, + A_DISP2_TBR, + A_DEC_R15, + A_INC_R15, + A_MOD, + A_RE, + A_RS, + A_DSR, + DSP_REG_M, + DSP_REG_N, + DSP_REG_X, + DSP_REG_Y, + DSP_REG_E, + DSP_REG_F, + DSP_REG_G, + DSP_REG_A_M, + DSP_REG_AX, + DSP_REG_XY, + DSP_REG_AY, + DSP_REG_YX, + AX_INC_N, + AY_INC_N, + AXY_INC_N, + AYX_INC_N, + AX_IND_N, + AY_IND_N, + AXY_IND_N, + AYX_IND_N, + AX_PMOD_N, + AXY_PMOD_N, + AY_PMOD_N, + AYX_PMOD_N, + AS_DEC_N, + AS_INC_N, + AS_IND_N, + AS_PMOD_N, + A_A0, + A_X0, + A_X1, + A_Y0, + A_Y1, + A_SSR, + A_SPC, + A_SGR, + A_DBR, + F_REG_N, + F_REG_M, + D_REG_N, + D_REG_M, + X_REG_N, /* Only used for argument parsing. */ + X_REG_M, /* Only used for argument parsing. */ + DX_REG_N, + DX_REG_M, + V_REG_N, + V_REG_M, + XMTRX_M4, + F_FR0, + FPUL_N, + FPUL_M, + FPSCR_N, + FPSCR_M + } +sh_arg_type; + +typedef enum + { + A_A1_NUM = 5, + A_A0_NUM = 7, + A_X0_NUM, A_X1_NUM, A_Y0_NUM, A_Y1_NUM, + A_M0_NUM, A_A1G_NUM, A_M1_NUM, A_A0G_NUM + } +sh_dsp_reg_nums; + +#define arch_sh1_base 0x0001 +#define arch_sh2_base 0x0002 +#define arch_sh3_base 0x0004 +#define arch_sh4_base 0x0008 +#define arch_sh4a_base 0x0010 +#define arch_sh2a_base 0x0020 + +/* This is an annotation on instruction types, but we abuse the arch + field in instructions to denote it. */ +#define arch_op32 0x00100000 /* This is a 32-bit opcode. */ + +#define arch_sh_no_mmu 0x04000000 +#define arch_sh_has_mmu 0x08000000 +#define arch_sh_no_co 0x10000000 /* neither FPU nor DSP co-processor */ +#define arch_sh_sp_fpu 0x20000000 /* single precision FPU */ +#define arch_sh_dp_fpu 0x40000000 /* double precision FPU */ +#define arch_sh_has_dsp 0x80000000 + + +#define arch_sh_base_mask 0x0000003f +#define arch_opann_mask 0x00100000 +#define arch_sh_mmu_mask 0x0c000000 +#define arch_sh_co_mask 0xf0000000 + + +#define arch_sh1 (arch_sh1_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2 (arch_sh2_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2a (arch_sh2a_base|arch_sh_no_mmu|arch_sh_dp_fpu) +#define arch_sh2a_nofpu (arch_sh2a_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2e (arch_sh2_base|arch_sh2a_base|arch_sh_no_mmu|arch_sh_sp_fpu) +#define arch_sh_dsp (arch_sh2_base|arch_sh_no_mmu|arch_sh_has_dsp) +#define arch_sh3_nommu (arch_sh3_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh3 (arch_sh3_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh3e (arch_sh3_base|arch_sh_has_mmu|arch_sh_sp_fpu) +#define arch_sh3_dsp (arch_sh3_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4 (arch_sh4_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4a (arch_sh4a_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4al_dsp (arch_sh4a_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4_nofpu (arch_sh4_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4a_nofpu (arch_sh4a_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4_nommu_nofpu (arch_sh4_base|arch_sh_no_mmu|arch_sh_no_co) + +#define SH_MERGE_ARCH_SET(SET1, SET2) ((SET1) & (SET2)) +#define SH_VALID_BASE_ARCH_SET(SET) (((SET) & arch_sh_base_mask) != 0) +#define SH_VALID_MMU_ARCH_SET(SET) (((SET) & arch_sh_mmu_mask) != 0) +#define SH_VALID_CO_ARCH_SET(SET) (((SET) & arch_sh_co_mask) != 0) +#define SH_VALID_ARCH_SET(SET) \ + (SH_VALID_BASE_ARCH_SET (SET) \ + && SH_VALID_MMU_ARCH_SET (SET) \ + && SH_VALID_CO_ARCH_SET (SET)) +#define SH_MERGE_ARCH_SET_VALID(SET1, SET2) \ + SH_VALID_ARCH_SET (SH_MERGE_ARCH_SET (SET1, SET2)) + +#define SH_ARCH_SET_HAS_FPU(SET) \ + (((SET) & (arch_sh_sp_fpu | arch_sh_dp_fpu)) != 0) +#define SH_ARCH_SET_HAS_DSP(SET) \ + (((SET) & arch_sh_has_dsp) != 0) + +/* This is returned from the functions below when an error occurs + (in addition to a call to BFD_FAIL). The value should allow + the tools to continue to function in most cases - there may + be some confusion between DSP and FPU etc. */ +#define SH_ARCH_UNKNOWN_ARCH 0xffffffff + +/* These are defined in bfd/cpu-sh.c . */ +unsigned int sh_get_arch_from_bfd_mach (unsigned long mach); +unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach); +unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set); +/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */ + +/* Below are the 'architecture sets'. + They describe the following inheritance graph: + + SH1 + | + SH2 + .------------'|`--------------------. + / | \ +SH-DSP SH3-nommu SH2E + | |`--------. | + | | \ | + | SH3 SH4-nommu-nofpu | + | | | | + | .------------'|`----------+---------. | + |/ / \| + | | .-------' | + | |/ | +SH3-dsp SH4-nofpu SH3E + | |`--------------------. | + | | \| + | SH4A-nofpu SH4 + | .------------' `--------------------. | + |/ \| +SH4AL-dsp SH4A + +*/ + +/* Central branches */ +#define arch_sh1_up (arch_sh1 | arch_sh2_up) +#define arch_sh2_up (arch_sh2 | arch_sh2e_up | arch_sh2a_nofpu_up | arch_sh3_nommu_up | arch_sh_dsp_up) +#define arch_sh3_nommu_up (arch_sh3_nommu | arch_sh3_up | arch_sh4_nommu_nofpu_up) +#define arch_sh3_up (arch_sh3 | arch_sh3e_up | arch_sh3_dsp_up | arch_sh4_nofp_up) +#define arch_sh4_nommu_nofpu_up (arch_sh4_nommu_nofpu | arch_sh4_nofp_up) +#define arch_sh4_nofp_up (arch_sh4_nofpu | arch_sh4_up | arch_sh4a_nofp_up) +#define arch_sh4a_nofp_up (arch_sh4a_nofpu | arch_sh4a_up | arch_sh4al_dsp_up) + +/* Right branch */ +#define arch_sh2e_up (arch_sh2e | arch_sh2a_up | arch_sh3e_up) +#define arch_sh3e_up (arch_sh3e | arch_sh4_up) +#define arch_sh4_up (arch_sh4 | arch_sh4a_up) +#define arch_sh4a_up (arch_sh4a) + +/* Left branch */ +#define arch_sh_dsp_up (arch_sh_dsp | arch_sh3_dsp_up) +#define arch_sh3_dsp_up (arch_sh3_dsp | arch_sh4al_dsp_up) +#define arch_sh4al_dsp_up (arch_sh4al_dsp) + +/* SH 2a branched off SH2e, adding a lot but not all of SH4 and SH4a. */ +#define arch_sh2a_up (arch_sh2a) +#define arch_sh2a_nofpu_up (arch_sh2a_nofpu | arch_sh2a_up) + + +typedef struct +{ + const char *name; + sh_arg_type arg[4]; + sh_nibble_type nibbles[9]; + unsigned int arch; +} sh_opcode_info; + +#ifdef DEFINE_TABLE + +const sh_opcode_info sh_table[] = + { +/* 0111nnnni8*1.... add #, */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1100 add , */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0011nnnnmmmm1110 addc ,*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0011nnnnmmmm1111 addv ,*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 11001001i8*1.... and #,R0 */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1001 and , */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 11001101i8*1.... and.b #,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM0_8}, arch_sh1_up}, + +/* 1010i12......... bra */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}, arch_sh1_up}, + +/* 1011i12......... bsr */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}, arch_sh1_up}, + +/* 10001001i8p1.... bt */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}, arch_sh1_up}, + +/* 10001011i8p1.... bf */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}, arch_sh1_up}, + +/* 10001101i8p1.... bt.s */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001101i8p1.... bt/s */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf.s */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf/s */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 0000000010001000 clrdmxy */{"clrdmxy",{0},{HEX_0,HEX_0,HEX_8,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000000101000 clrmac */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0000000001001000 clrs */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}, arch_sh1_up}, + +/* 0000000000001000 clrt */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}, arch_sh1_up}, + +/* 10001000i8*1.... cmp/eq #,R0 */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm0000 cmp/eq ,*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 0011nnnnmmmm0011 cmp/ge ,*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0011nnnnmmmm0111 cmp/gt ,*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0011nnnnmmmm0110 cmp/hi ,*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0011nnnnmmmm0010 cmp/hs ,*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010101 cmp/pl */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00010001 cmp/pz */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}, arch_sh1_up}, + +/* 0010nnnnmmmm1100 cmp/str ,*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0010nnnnmmmm0111 div0s ,*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0000000000011001 div0u */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0011nnnnmmmm0100 div1 ,*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm1110 exts.b ,*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1111 exts.w ,*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0110nnnnmmmm1100 extu.b ,*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm1101 extu.w ,*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnn11100011 icbi @ */{"icbi",{A_IND_N},{HEX_0,REG_N,HEX_E,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00101011 jmp @ */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001011 jsr @ */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001110 ldc ,SR */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00011110 ldc ,GBR */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00111010 ldc ,SGR */{"ldc",{A_REG_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100mmmm01001010 ldc ,TBR */{"ldc",{A_REG_M,A_TBR},{HEX_4,REG_M,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00101110 ldc ,VBR */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}, arch_sh1_up}, + +/* 0100nnnn01011110 ldc ,MOD */{"ldc",{A_REG_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01111110 ldc ,RE */{"ldc",{A_REG_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01101110 ldc ,RS */{"ldc",{A_REG_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn00111110 ldc ,SSR */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn01001110 ldc ,SPC */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn11111010 ldc ,DBR */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx1110 ldc ,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn00000111 ldc.l @+,SR */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010111 ldc.l @+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00100111 ldc.l @+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00110110 ldc.l @+,SGR */{"ldc.l",{A_INC_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn01010111 ldc.l @+,MOD */{"ldc.l",{A_INC_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01110111 ldc.l @+,RE */{"ldc.l",{A_INC_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01100111 ldc.l @+,RS */{"ldc.l",{A_INC_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn00110111 ldc.l @+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn01000111 ldc.l @+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn11110110 ldc.l @+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0111 ldc.l ,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}, arch_sh3_nommu_up}, + +/* 0100mmmm00110100 ldrc */{"ldrc",{A_REG_M},{HEX_4,REG_M,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* 10001010i8*1.... ldrc # */{"ldrc",{A_IMM},{HEX_8,HEX_A,IMM0_8}, arch_sh4al_dsp_up}, + +/* 10001110i8p2.... ldre @(,PC) */{"ldre",{A_DISP_PC},{HEX_8,HEX_E,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 10001100i8p2.... ldrs @(,PC) */{"ldrs",{A_DISP_PC},{HEX_8,HEX_C,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 0100nnnn00001010 lds ,MACH */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00011010 lds ,MACL */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00101010 lds ,PR */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0100nnnn01101010 lds ,DSR */{"lds",{A_REG_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01111010 lds ,A0 */{"lds",{A_REG_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10001010 lds ,X0 */{"lds",{A_REG_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10011010 lds ,X1 */{"lds",{A_REG_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10101010 lds ,Y0 */{"lds",{A_REG_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10111010 lds ,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00010110 lds.l @+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00100110 lds.l @+,PR */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}, arch_sh1_up}, + +/* 0100nnnn01100110 lds.l @+,DSR */{"lds.l",{A_INC_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 lds.l @+,A0 */{"lds.l",{A_INC_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 lds.l @+,X0 */{"lds.l",{A_INC_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 lds.l @+,X1 */{"lds.l",{A_INC_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 lds.l @+,Y0 */{"lds.l",{A_INC_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 lds.l @+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up}, + +/* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up}, + +/* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up}, + +/* 0100nnnnmmmm1111 mac.w @+,@+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 1110nnnni8*1.... mov #, */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0110nnnnmmmm0011 mov , */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0000nnnnmmmm0100 mov.b ,@(R0,)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0100 mov.b ,@-*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0000 mov.b ,@*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000100mmmmi4*1 mov.b @(,),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM0_4}, arch_sh1_up}, + +/* 11000100i8*1.... mov.b @(,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM0_8}, arch_sh1_up}, + +/* 0000nnnnmmmm1100 mov.b @(R0,),*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm0100 mov.b @+,*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm0000 mov.b @,*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000000mmmmi4*1 mov.b R0,@(,)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM1_4}, arch_sh1_up}, + +/* 11000000i8*1.... mov.b R0,@(,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM1_8}, arch_sh1_up}, + +/* 0100nnnn10001011 mov.b R0,@+ */{"mov.b",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_8,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.b @-,R0 */{"mov.b",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_C,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0000dddddddddddd mov.b ,@(,) */ +{"mov.b",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0100dddddddddddd mov.b @(,), */ +{"mov.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_4,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0001nnnnmmmmi4*4 mov.l ,@(,)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM1_4BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm0110 mov.l ,@(R0,)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0110 mov.l ,@-*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0010 mov.l ,@*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0101nnnnmmmmi4*4 mov.l @(,),*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM0_4BY4}, arch_sh1_up}, + +/* 11000110i8*4.... mov.l @(,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM0_8BY4}, arch_sh1_up}, + +/* 1101nnnni8p4.... mov.l @(,PC),*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm1110 mov.l @(R0,),*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm0110 mov.l @+,*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0110nnnnmmmm0010 mov.l @,*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 11000010i8*4.... mov.l R0,@(,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM1_8BY4}, arch_sh1_up}, + +/* 0100nnnn10101011 mov.l R0,@+ */{"mov.l",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_A,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.l @-,R0 */{"mov.l",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0010dddddddddddd mov.l ,@(,) */ +{"mov.l",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_2,DISP1_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0110dddddddddddd mov.l @(,), */ +{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_6,DISP0_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnnmmmm0101 mov.w ,@(R0,)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0101 mov.w ,@-*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0001 mov.w ,@*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000101mmmmi4*2 mov.w @(,),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM0_4BY2}, arch_sh1_up}, + +/* 11000101i8*2.... mov.w @(,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM0_8BY2}, arch_sh1_up}, + +/* 1001nnnni8p2.... mov.w @(,PC),*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}, arch_sh1_up}, + +/* 0000nnnnmmmm1101 mov.w @(R0,),*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0110nnnnmmmm0101 mov.w @+,*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0110nnnnmmmm0001 mov.w @,*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000001mmmmi4*2 mov.w R0,@(,)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM1_4BY2}, arch_sh1_up}, + +/* 11000001i8*2.... mov.w R0,@(,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM1_8BY2}, arch_sh1_up}, + +/* 0100nnnn10011011 mov.w R0,@+ */{"mov.w",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_9,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11011011 mov.w @-,R0 */{"mov.w",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_D,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0001dddddddddddd mov.w ,@(,) */ +{"mov.w",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_1,DISP1_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0101dddddddddddd mov.w @(,), */ +{"mov.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_5,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 11000111i8p4.... mova @(,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}, arch_sh1_up}, +/* 0000nnnn11000011 movca.l R0,@ */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn01110011 movco.l r0,@ */{"movco.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_7,HEX_3}, arch_sh4a_nofp_up}, +/* 0000mmmm01100011 movli.l @,r0 */{"movli.l",{A_IND_M,A_R0},{HEX_0,REG_M,HEX_6,HEX_3}, arch_sh4a_nofp_up}, + +/* 0000nnnn00101001 movt */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100mmmm10101001 movua.l @,r0 */{"movua.l",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_A,HEX_9}, arch_sh4a_nofp_up}, +/* 0100mmmm11101001 movua.l @+,r0 */{"movua.l",{A_INC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_9}, arch_sh4a_nofp_up}, + +/* 0010nnnnmmmm1111 muls.w ,*/{"muls.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, +/* 0010nnnnmmmm1111 muls ,*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh2_up}, + +/* 0010nnnnmmmm1110 mulu.w ,*/{"mulu.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, +/* 0010nnnnmmmm1110 mulu ,*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1011 neg , */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1010 negc ,*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0000000000001001 nop */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0110nnnnmmmm0111 not , */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}, arch_sh1_up}, +/* 0000nnnn10010011 ocbi @ */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10100011 ocbp @ */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10110011 ocbwb @ */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}, arch_sh4_nommu_nofpu_up}, + + +/* 11001011i8*1.... or #,R0 */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1011 or , */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 11001111i8*1.... or.b #,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM0_8}, arch_sh1_up}, + +/* 0000nnnn10000011 pref @ */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}, arch_sh4_nommu_nofpu_up | arch_sh2a_nofpu_up}, + +/* 0000nnnn11010011 prefi @ */{"prefi",{A_IND_N},{HEX_0,REG_N,HEX_D,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00100100 rotcl */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00100101 rotcr */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00000100 rotl */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00000101 rotr */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}, arch_sh1_up}, + +/* 0000000000101011 rte */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0000000000001011 rts */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0000000010011000 setdmx */{"setdmx",{0},{HEX_0,HEX_0,HEX_9,HEX_8}, arch_sh4al_dsp_up}, +/* 0000000011001000 setdmy */{"setdmy",{0},{HEX_0,HEX_0,HEX_C,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000001011000 sets */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}, arch_sh1_up}, +/* 0000000000011000 sett */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00010100 setrc */{"setrc",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* 10000010i8*1.... setrc # */{"setrc",{A_IMM},{HEX_8,HEX_2,IMM0_8}, arch_sh_dsp_up}, + +/* repeat start end */{"repeat",{A_DISP_PC,A_DISP_PC,A_REG_N},{REPEAT,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* repeat start end # */{"repeat",{A_DISP_PC,A_DISP_PC,A_IMM},{REPEAT,HEX_2,IMM0_8,HEX_8}, arch_sh_dsp_up}, + +/* 0100nnnnmmmm1100 shad ,*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnnmmmm1101 shld ,*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnn00100000 shal */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00100001 shar */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00000000 shll */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00101000 shll16 */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00001000 shll2 */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00011000 shll8 */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00000001 shlr */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00101001 shlr16 */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00001001 shlr2 */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00011001 shlr8 */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0000000000011011 sleep */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}, arch_sh1_up}, + +/* 0000nnnn00000010 stc SR, */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00010010 stc GBR, */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00100010 stc VBR, */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0000nnnn01010010 stc MOD, */{"stc",{A_MOD,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01110010 stc RE, */{"stc",{A_RE,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01100010 stc RS, */{"stc",{A_RS,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn00110010 stc SSR, */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01000010 stc SPC, */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn00111010 stc SGR, */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn11111010 stc DBR, */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn1xxx0010 stc Rn_BANK, */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01001010 stc TBR, */ {"stc",{A_TBR,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00000011 stc.l SR,@- */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00100011 stc.l VBR,@- */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}, arch_sh1_up}, + +/* 0100nnnn01010011 stc.l MOD,@- */{"stc.l",{A_MOD,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01110011 stc.l RE,@- */{"stc.l",{A_RE,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01100011 stc.l RS,@- */{"stc.l",{A_RS,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn00110011 stc.l SSR,@- */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn01000011 stc.l SPC,@- */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn00010011 stc.l GBR,@- */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00110010 stc.l SGR,@- */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn11110010 stc.l DBR,@- */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_F,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0011 stc.l Rn_BANK,@- */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}, arch_sh3_nommu_up}, + +/* 0000nnnn00001010 sts MACH, */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00011010 sts MACL, */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00101010 sts PR, */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0000nnnn01101010 sts DSR, */{"sts",{A_DSR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01111010 sts A0, */{"sts",{A_A0,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10001010 sts X0, */{"sts",{A_X0,A_REG_N},{HEX_0,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10011010 sts X1, */{"sts",{A_X1,A_REG_N},{HEX_0,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10101010 sts Y0, */{"sts",{A_Y0,A_REG_N},{HEX_0,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10111010 sts Y1, */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010010 sts.l MACL,@-*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00100010 sts.l PR,@- */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0100nnnn01100110 sts.l DSR,@- */{"sts.l",{A_DSR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 sts.l A0,@- */{"sts.l",{A_A0,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 sts.l X0,@- */{"sts.l",{A_X0,A_DEC_N},{HEX_4,REG_N,HEX_8,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 sts.l X1,@- */{"sts.l",{A_X1,A_DEC_N},{HEX_4,REG_N,HEX_9,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 sts.l Y0,@- */{"sts.l",{A_Y0,A_DEC_N},{HEX_4,REG_N,HEX_A,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 sts.l Y1,@- */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up}, + +/* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up}, + +/* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1010 subc ,*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0011nnnnmmmm1011 subv ,*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1000 swap.b ,*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0110nnnnmmmm1001 swap.w ,*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 0000000010101011 synco */{"synco",{0},{HEX_0,HEX_0,HEX_A,HEX_B}, arch_sh4a_nofp_up}, + +/* 0100nnnn00011011 tas.b @ */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}, arch_sh1_up}, + +/* 11000011i8*1.... trapa # */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM0_8}, arch_sh1_up}, + +/* 11001000i8*1.... tst #,R0 */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1000 tst , */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 11001100i8*1.... tst.b #,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM0_8}, arch_sh1_up}, + +/* 11001010i8*1.... xor #,R0 */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1010 xor , */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 11001110i8*1.... xor.b #,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1101 xtrct ,*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010000 dt */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}, arch_sh2_up}, + +/* 0011nnnnmmmm1101 dmuls.l ,*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}, arch_sh2_up}, + +/* 0011nnnnmmmm0101 dmulu.l ,*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}, arch_sh2_up}, + +/* 0000nnnnmmmm1111 mac.l @+,@+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}, arch_sh2_up}, + +/* 0000nnnn00100011 braf */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}, arch_sh2_up}, + +/* 0000nnnn00000011 bsrf */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}, arch_sh2_up}, + +/* 111101nnmmmm0000 movs.w @-, */ {"movs.w",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_0}, arch_sh_dsp_up}, + +/* 111101nnmmmm0001 movs.w @, */ {"movs.w",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_4}, arch_sh_dsp_up}, + +/* 111101nnmmmm0010 movs.w @+, */ {"movs.w",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_8}, arch_sh_dsp_up}, + +/* 111101nnmmmm0011 movs.w @+r8, */ {"movs.w",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_C}, arch_sh_dsp_up}, + +/* 111101nnmmmm0100 movs.w ,@- */ {"movs.w",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_1}, arch_sh_dsp_up}, + +/* 111101nnmmmm0101 movs.w ,@ */ {"movs.w",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_5}, arch_sh_dsp_up}, + +/* 111101nnmmmm0110 movs.w ,@+ */ {"movs.w",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_9}, arch_sh_dsp_up}, + +/* 111101nnmmmm0111 movs.w ,@+r8 */ {"movs.w",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_D}, arch_sh_dsp_up}, + +/* 111101nnmmmm1000 movs.l @-, */ {"movs.l",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_2}, arch_sh_dsp_up}, + +/* 111101nnmmmm1001 movs.l @, */ {"movs.l",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_6}, arch_sh_dsp_up}, + +/* 111101nnmmmm1010 movs.l @+, */ {"movs.l",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_A}, arch_sh_dsp_up}, + +/* 111101nnmmmm1011 movs.l @+r8, */ {"movs.l",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_E}, arch_sh_dsp_up}, + +/* 111101nnmmmm1100 movs.l ,@- */ {"movs.l",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_3}, arch_sh_dsp_up}, + +/* 111101nnmmmm1101 movs.l ,@ */ {"movs.l",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_7}, arch_sh_dsp_up}, + +/* 111101nnmmmm1110 movs.l ,@+ */ {"movs.l",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_B}, arch_sh_dsp_up}, + +/* 111101nnmmmm1111 movs.l ,@+r8 */ {"movs.l",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_F}, arch_sh_dsp_up}, + +/* 0*0*0*00** nopx */ {"nopx",{0},{PPI,NOPX}, arch_sh_dsp_up}, +/* *0*0*0**00 nopy */ {"nopy",{0},{PPI,NOPY}, arch_sh_dsp_up}, +/* n*m*0*01** movx.w @, */ {"movx.w",{AX_IND_N,DSP_REG_X},{PPI,MOVX,HEX_1}, arch_sh_dsp_up}, +/* n*m*0*10** movx.w @+, */ {"movx.w",{AX_INC_N,DSP_REG_X},{PPI,MOVX,HEX_2}, arch_sh_dsp_up}, +/* n*m*0*11** movx.w @+r8, */ {"movx.w",{AX_PMOD_N,DSP_REG_X},{PPI,MOVX,HEX_3}, arch_sh_dsp_up}, +/* n*m*1*01** movx.w ,@ */ {"movx.w",{DSP_REG_A_M,AX_IND_N},{PPI,MOVX,HEX_9}, arch_sh_dsp_up}, +/* n*m*1*10** movx.w ,@+ */ {"movx.w",{DSP_REG_A_M,AX_INC_N},{PPI,MOVX,HEX_A}, arch_sh_dsp_up}, +/* n*m*1*11** movx.w ,@+r8 */ {"movx.w",{DSP_REG_A_M,AX_PMOD_N},{PPI,MOVX,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000100 movx.w @, */ {"movx.w",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm001000 movx.w @+, */{"movx.w",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm001100 movx.w @+r8, */{"movx.w",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm100100 movx.w ,@ */ {"movx.w",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_2,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm101000 movx.w ,@+ */{"movx.w",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_2,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm101100 movx.w ,@+r8 */{"movx.w",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_2,HEX_C}, arch_sh4al_dsp_up}, + +/* nnmm010100 movx.l @, */ {"movx.l",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm011000 movx.l @+, */{"movx.l",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm011100 movx.l @+r8, */{"movx.l",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm110100 movx.l ,@ */ {"movx.l",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm111000 movx.l ,@+ */{"movx.l",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_3,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm111100 movx.l ,@+r8 */{"movx.l",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_3,HEX_C}, arch_sh4al_dsp_up}, + +/* *n*m*0**01 movy.w @, */ {"movy.w",{AY_IND_N,DSP_REG_Y},{PPI,MOVY,HEX_1}, arch_sh_dsp_up}, +/* *n*m*0**10 movy.w @+, */ {"movy.w",{AY_INC_N,DSP_REG_Y},{PPI,MOVY,HEX_2}, arch_sh_dsp_up}, +/* *n*m*0**11 movy.w @+r9, */ {"movy.w",{AY_PMOD_N,DSP_REG_Y},{PPI,MOVY,HEX_3}, arch_sh_dsp_up}, +/* *n*m*1**01 movy.w ,@ */ {"movy.w",{DSP_REG_A_M,AY_IND_N},{PPI,MOVY,HEX_9}, arch_sh_dsp_up}, +/* *n*m*1**10 movy.w ,@+ */ {"movy.w",{DSP_REG_A_M,AY_INC_N},{PPI,MOVY,HEX_A}, arch_sh_dsp_up}, +/* *n*m*1**11 movy.w ,@+r9 */ {"movy.w",{DSP_REG_A_M,AY_PMOD_N},{PPI,MOVY,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000001 movy.w @, */ {"movy.w",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm000010 movy.w @+, */{"movy.w",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm000011 movy.w @+r8, */{"movy.w",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm010001 movy.w ,@ */ {"movy.w",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_1,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm010010 movy.w ,@+ */{"movy.w",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_1,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm010011 movy.w ,@+r8 */{"movy.w",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_1,HEX_3}, arch_sh4al_dsp_up}, + +/* nnmm100001 movy.l @, */ {"movy.l",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm100010 movy.l @+, */{"movy.l",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm100011 movy.l @+r8, */{"movy.l",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm110001 movy.l ,@ */ {"movy.l",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_3,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm110010 movy.l ,@+ */{"movy.l",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_3,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm110011 movy.l ,@+r8 */{"movy.l",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_3,HEX_3}, arch_sh4al_dsp_up}, + +/* 01aaeeffxxyyggnn pmuls Se,Sf,Dg */ {"pmuls",{DSP_REG_E,DSP_REG_F,DSP_REG_G},{PPI,PMUL}, arch_sh_dsp_up}, +/* 10100000xxyynnnn psubc ,, */ +{"psubc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_0}, arch_sh_dsp_up}, +/* 10110000xxyynnnn paddc ,, */ +{"paddc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_0}, arch_sh_dsp_up}, +/* 10000100xxyynnnn pcmp , */ +{"pcmp", {DSP_REG_X,DSP_REG_Y},{PPI,PPI3,HEX_8,HEX_4}, arch_sh_dsp_up}, +/* 10100100xxyynnnn pwsb ,, */ +{"pwsb", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_4}, arch_sh_dsp_up}, +/* 10110100xxyynnnn pwad ,, */ +{"pwad", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_4}, arch_sh_dsp_up}, +/* 10001000xxyynnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_8,HEX_8}, arch_sh_dsp_up}, +/* 1000100!xx01nnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10101000xxyynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_A,HEX_8}, arch_sh_dsp_up}, +/* 1010100!01yynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9,HEX_4}, arch_sh4al_dsp_up}, +/* 10011000xxyynnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_9,HEX_8}, arch_sh_dsp_up}, +/* 1001100!xx01nnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10111000xxyynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_B,HEX_8}, arch_sh_dsp_up}, +/* 1011100!01yynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_4}, arch_sh4al_dsp_up}, + +{"dct",{0},{PPI,PDC,HEX_1}, arch_sh_dsp_up}, +{"dcf",{0},{PPI,PDC,HEX_2}, arch_sh_dsp_up}, + +/* 10000001xxyynnnn pshl ,, */ +{"pshl", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_1}, arch_sh_dsp_up}, +/* 00000iiiiiiinnnn pshl #, */ {"pshl",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_0}, arch_sh_dsp_up}, +/* 10010001xxyynnnn psha ,, */ +{"psha", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_1}, arch_sh_dsp_up}, +/* 00010iiiiiiinnnn psha #, */ {"psha",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_1}, arch_sh_dsp_up}, +/* 10100001xxyynnnn psub ,, */ +{"psub", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_1}, arch_sh_dsp_up}, +/* 10000101xxyynnnn psub ,, */ +{"psub", {DSP_REG_Y,DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_5}, arch_sh4al_dsp_up}, +/* 10110001xxyynnnn padd ,, */ +{"padd", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_1}, arch_sh_dsp_up}, +/* 10010101xxyynnnn pand ,, */ +{"pand", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_5}, arch_sh_dsp_up}, +/* 10100101xxyynnnn pxor ,, */ +{"pxor", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_5}, arch_sh_dsp_up}, +/* 10110101xxyynnnn por ,, */ +{"por", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_5}, arch_sh_dsp_up}, +/* 10001001xxyynnnn pdec , */ +{"pdec", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9}, arch_sh_dsp_up}, +/* 10101001xxyynnnn pdec , */ +{"pdec", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9}, arch_sh_dsp_up}, +/* 10011001xx00nnnn pinc , */ +{"pinc", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_XX00}, arch_sh_dsp_up}, +/* 1011100100yynnnn pinc , */ +{"pinc", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_00YY}, arch_sh_dsp_up}, +/* 10001101xxyynnnn pclr */ +{"pclr", {DSP_REG_N},{PPI,PPIC,HEX_8,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx00nnnn pdmsb , */ +{"pdmsb", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_XX00}, arch_sh_dsp_up}, +/* 1011110100yynnnn pdmsb , */ +{"pdmsb", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_00YY}, arch_sh_dsp_up}, +/* 11001001xxyynnnn pneg , */ +{"pneg", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_9}, arch_sh_dsp_up}, +/* 11101001xxyynnnn pneg , */ +{"pneg", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_E,HEX_9}, arch_sh_dsp_up}, +/* 11011001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_9}, arch_sh_dsp_up}, +/* 11111001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_F,HEX_9}, arch_sh_dsp_up}, +/* 11001101xxyynnnn psts MACH, */ +{"psts", {A_MACH,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_D}, arch_sh_dsp_up}, +/* 11011101xxyynnnn psts MACL, */ +{"psts", {A_MACL,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_D}, arch_sh_dsp_up}, +/* 11101101xxyynnnn plds ,MACH */ +{"plds", {DSP_REG_N,A_MACH},{PPI,PPIC,HEX_E,HEX_D}, arch_sh_dsp_up}, +/* 11111101xxyynnnn plds ,MACL */ +{"plds", {DSP_REG_N,A_MACL},{PPI,PPIC,HEX_F,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx01zzzz pswap , */ +{"pswap", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_1}, arch_sh4al_dsp_up}, +/* 1011110101yyzzzz pswap , */ +{"pswap", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_4}, arch_sh4al_dsp_up}, + +/* 1111nnnn01011101 fabs */{"fabs",{F_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh2e_up}, +/* 1111nnn001011101 fabs */{"fabs",{D_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0000 fadd ,*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh2e_up}, +/* 1111nnn0mmm00000 fadd ,*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0100 fcmp/eq ,*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh2e_up}, +/* 1111nnn0mmm00100 fcmp/eq ,*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0101 fcmp/gt ,*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh2e_up}, +/* 1111nnn0mmm00101 fcmp/gt ,*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010111101 fcnvds ,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N_D,HEX_B,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010101101 fcnvsd FPUL,*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_A,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0011 fdiv ,*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh2e_up}, +/* 1111nnn0mmm00011 fdiv ,*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnmm11101101 fipr ,*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}, arch_sh4_up}, + +/* 1111nnnn10001101 fldi0 */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn10011101 fldi1 */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00011101 flds ,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00101101 float FPUL,*/{"float",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh2e_up}, +/* 1111nnn000101101 float FPUL,*/{"float",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1110 fmac FR0,,*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}, arch_sh2e_up}, + +/* 1111nnnnmmmm1100 fmov ,*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh2e_up}, +/* 1111nnn1mmmm1100 fmov ,*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1000 fmov @,*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, +/* 1111nnn1mmmm1000 fmov @,*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1010 fmov ,@*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, +/* 1111nnnnmmm11010 fmov ,@*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1001 fmov @+,*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, +/* 1111nnn1mmmm1001 fmov @+,*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1011 fmov ,@-*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, +/* 1111nnnnmmm11011 fmov ,@-*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, +/* 1111nnn1mmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0111 fmov ,@(R0,)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 1111nnnnmmm10111 fmov ,@(R0,)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1000 fmov.d @,*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11010 fmov.d ,@*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1001 fmov.d @+,*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11011 fmov.d ,@-*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm0110 fmov.d @(R0,),*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm10111 fmov.d ,@(R0,)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.d ,@(,) */ +{"fmov.d",{DX_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY8}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.d @(,),F_REG_N */ +{"fmov.d",{A_DISP_REG_M,DX_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY8}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm1000 fmov.s @,*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, + +/* 1111nnnnmmmm1010 fmov.s ,@*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, + +/* 1111nnnnmmmm1001 fmov.s @+,*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, + +/* 1111nnnnmmmm1011 fmov.s ,@-*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, + +/* 1111nnnnmmmm0110 fmov.s @(R0,),*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, + +/* 1111nnnnmmmm0111 fmov.s ,@(R0,)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.s ,@(,) */ +{"fmov.s",{F_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY4}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.s @(,),F_REG_N */ +{"fmov.s",{A_DISP_REG_M,F_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY4}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm0010 fmul ,*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh2e_up}, +/* 1111nnn0mmm00010 fmul ,*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01001101 fneg */{"fneg",{F_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh2e_up}, +/* 1111nnn001001101 fneg */{"fneg",{D_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111011111111101 fpchg */{"fpchg",{0},{HEX_F,HEX_7,HEX_F,HEX_D}, arch_sh4a_up}, + +/* 1111101111111101 frchg */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111nnn011111101 fsca FPUL, */{"fsca",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111001111111101 fschg */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01101101 fsqrt */{"fsqrt",{F_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh3e_up | arch_sh2a_up}, +/* 1111nnn001101101 fsqrt */{"fsqrt",{D_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01111101 fsrra */{"fsrra",{F_REG_N},{HEX_F,REG_N,HEX_7,HEX_D}, arch_sh4_up}, + +/* 1111nnnn00001101 fsts FPUL,*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}, arch_sh2e_up}, + +/* 1111nnnnmmmm0001 fsub ,*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh2e_up}, +/* 1111nnn0mmm00001 fsub ,*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh2e_up}, +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nn0111111101 ftrv XMTRX_M4,*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_N_B01,HEX_F,HEX_D}, arch_sh4_up}, + + /* 10000110nnnn0iii bclr #, */ {"bclr",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0000dddddddddddd bclr.b #,@(,) */ +{"bclr.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn1iii bld #, */ {"bld",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0011dddddddddddd bld.b #,@(,) */ +{"bld.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_3,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000110nnnn1iii bset #, */ {"bset",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0001dddddddddddd bset.b #,@(,) */ +{"bset.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_1,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn0iii bst #, */ {"bst",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0010dddddddddddd bst.b #,@(,) */ +{"bst.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_2,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 0100nnnn10010001 clips.b */ {"clips.b",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010101 clips.w */ {"clips.w",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000001 clipu.b */ {"clipu.b",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000101 clipu.w */ {"clipu.w",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010100 divs R0, */ {"divs",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_9,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000100 divu R0, */ {"divu",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100mmmm01001011 jsr/n @ */ {"jsr/n",{A_IND_M},{HEX_4,REG_M,HEX_4,HEX_B}, arch_sh2a_nofpu_up}, + /* 10000011dddddddd jsr/n @@(,TBR) */ {"jsr/n",{A_DISP2_TBR},{HEX_8,HEX_3,IMM0_8BY4}, arch_sh2a_nofpu_up}, + /* 0100mmmm11100101 ldbank @,R0 */ {"ldbank",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110001 movml.l ,@-R15 */ {"movml.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110101 movml.l @R15+, */ {"movml.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110000 movml.l ,@-R15 */ {"movmu.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_0}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110100 movml.l @R15+, */ {"movmu.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_4}, arch_sh2a_nofpu_up}, + /* 0000nnnn00111001 movrt */ {"movrt",{A_REG_N},{HEX_0,REG_N,HEX_3,HEX_9}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000000 mulr R0, */ {"mulr",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_0}, arch_sh2a_nofpu_up}, + /* 0000000001101000 nott */ {"nott",{A_END},{HEX_0,HEX_0,HEX_6,HEX_8}, arch_sh2a_nofpu_up}, + /* 0000000001011011 resbank */ {"resbank",{A_END},{HEX_0,HEX_0,HEX_5,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000000001101011 rts/n */ {"rts/n",{A_END},{HEX_0,HEX_0,HEX_6,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000mmmm01111011 rtv/n */ {"rtv/n",{A_REG_M},{HEX_0,REG_M,HEX_7,HEX_B}, arch_sh2a_nofpu_up}, + /* 0100nnnn11100001 stbank R0,@*/ {"stbank",{A_R0,A_IND_N},{HEX_4,REG_N,HEX_E,HEX_1}, arch_sh2a_nofpu_up}, + +/* 0011nnnn0iii1001 0100dddddddddddd band.b #,@(,) */ +{"band.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_4,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1100dddddddddddd bandnot.b #,@(,) */ +{"bandnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_C,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1011dddddddddddd bldnot.b #,@(,) */ +{"bldnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_B,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0101dddddddddddd bor.b #,@(,) */ +{"bor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_5,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1101dddddddddddd bornot.b #,@(,) */ +{"bornot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_D,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0110dddddddddddd bxor.b #,@(,) */ +{"bxor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_6,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0000 iiiiiiiiiiiiiiii movi20 #, */ +{"movi20",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_0,IMM0_20}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0001 iiiiiiiiiiiiiiii movi20s #, */ +{"movi20s",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_1,IMM0_20BY8}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1000dddddddddddd movu.b @(,), */ +{"movu.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_8,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(,), */ +{"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, + +{ 0, {0}, {0}, 0 } +}; + +#endif + +#ifdef ARCH_all +#define INCLUDE_SHMEDIA +#endif + +static void print_movxy + (const sh_opcode_info *, int, int, fprintf_ftype, void *); +static void print_insn_ddt (int, struct disassemble_info *); +static void print_dsp_reg (int, fprintf_ftype, void *); +static void print_insn_ppi (int, struct disassemble_info *); + +static void +print_movxy (const sh_opcode_info *op, int rn, int rm, + fprintf_ftype fprintf_fn, void *stream) +{ + int n; + + fprintf_fn (stream, "%s\t", op->name); + for (n = 0; n < 2; n++) + { + switch (op->arg[n]) + { + case A_IND_N: + case AX_IND_N: + case AXY_IND_N: + case AY_IND_N: + case AYX_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_INC_N: + case AX_INC_N: + case AXY_INC_N: + case AY_INC_N: + case AYX_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case AX_PMOD_N: + case AXY_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case AY_PMOD_N: + case AYX_PMOD_N: + fprintf_fn (stream, "@r%d+r9", rn); + break; + case DSP_REG_A_M: + fprintf_fn (stream, "a%c", '0' + rm); + break; + case DSP_REG_X: + fprintf_fn (stream, "x%c", '0' + rm); + break; + case DSP_REG_Y: + fprintf_fn (stream, "y%c", '0' + rm); + break; + case DSP_REG_AX: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'x' : 'a', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_XY: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'y' : 'x', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_AY: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'y' : 'a', + (rm & 1) ? '1' : '0'); + break; + case DSP_REG_YX: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'x' : 'y', + (rm & 1) ? '1' : '0'); + break; + default: + abort (); + } + if (n == 0) + fprintf_fn (stream, ","); + } +} + +/* Print a double data transfer insn. INSN is just the lower three + nibbles of the insn, i.e. field a and the bit that indicates if + a parallel processing insn follows. + Return nonzero if a field b of a parallel processing insns follows. */ + +static void +print_insn_ddt (int insn, struct disassemble_info *info) +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + + /* If this is just a nop, make sure to emit something. */ + if (insn == 0x000) + fprintf_fn (stream, "nopx\tnopy"); + + /* If a parallel processing insn was printed before, + and we got a non-nop, emit a tab. */ + if ((insn & 0x800) && (insn & 0x3ff)) + fprintf_fn (stream, "\t"); + + /* Check if either the x or y part is invalid. */ + if (((insn & 0xc) == 0 && (insn & 0x2a0)) + || ((insn & 3) == 0 && (insn & 0x150))) + if (info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *op; + int is_movy; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;) + first_movy++; + } + + is_movy = ((insn & 3) != 0); + + if (is_movy) + op = first_movy; + else + op = first_movx; + + while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3) + || op->nibbles[3] != (unsigned) (insn & 0xf)) + op++; + + print_movxy (op, + (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0) + + 2 * is_movy + + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)), + (insn >> 6) & 3, + fprintf_fn, stream); + } + else + fprintf_fn (stream, ".word 0x%x", insn); + else + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *opx, *opy; + unsigned int insn_x, insn_y; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;) + first_movy++; + } + insn_x = (insn >> 2) & 0xb; + if (insn_x) + { + for (opx = first_movx; opx->nibbles[2] != insn_x;) + opx++; + print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1, + fprintf_fn, stream); + } + insn_y = (insn & 3) | ((insn >> 1) & 8); + if (insn_y) + { + if (insn_x) + fprintf_fn (stream, "\t"); + for (opy = first_movy; opy->nibbles[2] != insn_y;) + opy++; + print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1, + fprintf_fn, stream); + } + } +} + +static void +print_dsp_reg (int rm, fprintf_ftype fprintf_fn, void *stream) +{ + switch (rm) + { + case A_A1_NUM: + fprintf_fn (stream, "a1"); + break; + case A_A0_NUM: + fprintf_fn (stream, "a0"); + break; + case A_X0_NUM: + fprintf_fn (stream, "x0"); + break; + case A_X1_NUM: + fprintf_fn (stream, "x1"); + break; + case A_Y0_NUM: + fprintf_fn (stream, "y0"); + break; + case A_Y1_NUM: + fprintf_fn (stream, "y1"); + break; + case A_M0_NUM: + fprintf_fn (stream, "m0"); + break; + case A_A1G_NUM: + fprintf_fn (stream, "a1g"); + break; + case A_M1_NUM: + fprintf_fn (stream, "m1"); + break; + case A_A0G_NUM: + fprintf_fn (stream, "a0g"); + break; + default: + fprintf_fn (stream, "0x%x", rm); + break; + } +} + +static void +print_insn_ppi (int field_b, struct disassemble_info *info) +{ + static const char *sx_tab[] = { "x0", "x1", "a0", "a1" }; + static const char *sy_tab[] = { "y0", "y1", "m0", "m1" }; + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned int nib1, nib2, nib3; + unsigned int altnib1, nib4; + const char *dc = NULL; + const sh_opcode_info *op; + + if ((field_b & 0xe800) == 0) + { + fprintf_fn (stream, "psh%c\t#%d,", + field_b & 0x1000 ? 'a' : 'l', + (field_b >> 4) & 127); + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + return; + } + if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000) + { + static const char *du_tab[] = { "x0", "y0", "a0", "a1" }; + static const char *se_tab[] = { "x0", "x1", "y0", "a1" }; + static const char *sf_tab[] = { "y0", "y1", "x0", "a1" }; + static const char *sg_tab[] = { "m0", "m1", "a0", "a1" }; + + if (field_b & 0x2000) + { + fprintf_fn (stream, "p%s %s,%s,%s\t", + (field_b & 0x1000) ? "add" : "sub", + sx_tab[(field_b >> 6) & 3], + sy_tab[(field_b >> 4) & 3], + du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf0) == 0x10 + && info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf3) != 0) + { + fprintf_fn (stream, ".word 0x%x\t", field_b); + } + fprintf_fn (stream, "pmuls%c%s,%s,%s", + field_b & 0x2000 ? ' ' : '\t', + se_tab[(field_b >> 10) & 3], + sf_tab[(field_b >> 8) & 3], + sg_tab[(field_b >> 2) & 3]); + return; + } + + nib1 = PPIC; + nib2 = field_b >> 12 & 0xf; + nib3 = field_b >> 8 & 0xf; + nib4 = field_b >> 4 & 0xf; + switch (nib3 & 0x3) + { + case 0: + dc = ""; + nib1 = PPI3; + break; + case 1: + dc = ""; + break; + case 2: + dc = "dct "; + nib3 -= 1; + break; + case 3: + dc = "dcf "; + nib3 -= 2; + break; + } + if (nib1 == PPI3) + altnib1 = PPI3NC; + else + altnib1 = nib1; + for (op = sh_table; op->name; op++) + { + if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1) + && op->nibbles[2] == nib2 + && op->nibbles[3] == nib3) + { + int n; + + switch (op->nibbles[4]) + { + case HEX_0: + break; + case HEX_XX00: + if ((nib4 & 3) != 0) + continue; + break; + case HEX_1: + if ((nib4 & 3) != 1) + continue; + break; + case HEX_00YY: + if ((nib4 & 0xc) != 0) + continue; + break; + case HEX_4: + if ((nib4 & 0xc) != 4) + continue; + break; + default: + abort (); + } + fprintf_fn (stream, "%s%s\t", dc, op->name); + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case DSP_REG_N: + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + break; + case DSP_REG_X: + fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]); + break; + case DSP_REG_Y: + fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + default: + abort (); + } + } + return; + } + } + /* Not found. */ + fprintf_fn (stream, ".word 0x%x", field_b); +} + +/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff + (ie. the upper nibble is missing). */ +int +print_insn_sh (bfd_vma memaddr, struct disassemble_info *info) +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned char insn[4]; + unsigned char nibs[8]; + int status; + bfd_vma relmask = ~(bfd_vma) 0; + const sh_opcode_info *op; + unsigned int target_arch; + int allow_op32; + + switch (info->mach) + { + case bfd_mach_sh: + target_arch = arch_sh1; + break; + case bfd_mach_sh4: + target_arch = arch_sh4; + break; + case bfd_mach_sh5: +#ifdef INCLUDE_SHMEDIA + status = print_insn_sh64 (memaddr, info); + if (status != -2) + return status; +#endif + /* When we get here for sh64, it's because we want to disassemble + SHcompact, i.e. arch_sh4. */ + target_arch = arch_sh4; + break; + default: + fprintf (stderr, "sh architecture not supported\n"); + return -1; + } + + status = info->read_memory_func (memaddr, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[0] = (insn[1] >> 4) & 0xf; + nibs[1] = insn[1] & 0xf; + + nibs[2] = (insn[0] >> 4) & 0xf; + nibs[3] = insn[0] & 0xf; + } + else + { + nibs[0] = (insn[0] >> 4) & 0xf; + nibs[1] = insn[0] & 0xf; + + nibs[2] = (insn[1] >> 4) & 0xf; + nibs[3] = insn[1] & 0xf; + } + status = info->read_memory_func (memaddr + 2, insn + 2, 2, info); + if (status != 0) + allow_op32 = 0; + else + { + allow_op32 = 1; + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[4] = (insn[3] >> 4) & 0xf; + nibs[5] = insn[3] & 0xf; + + nibs[6] = (insn[2] >> 4) & 0xf; + nibs[7] = insn[2] & 0xf; + } + else + { + nibs[4] = (insn[2] >> 4) & 0xf; + nibs[5] = insn[2] & 0xf; + + nibs[6] = (insn[3] >> 4) & 0xf; + nibs[7] = insn[3] & 0xf; + } + } + + if (nibs[0] == 0xf && (nibs[1] & 4) == 0 + && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up)) + { + if (nibs[1] & 8) + { + int field_b; + + status = info->read_memory_func (memaddr + 2, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr + 2, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + field_b = insn[1] << 8 | insn[0]; + else + field_b = insn[0] << 8 | insn[1]; + + print_insn_ppi (field_b, info); + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 4; + } + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 2; + } + for (op = sh_table; op->name; op++) + { + int n; + int imm = 0; + int rn = 0; + int rm = 0; + int rb = 0; + int disp_pc; + bfd_vma disp_pc_addr = 0; + int disp = 0; + int has_disp = 0; + int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4; + + if (!allow_op32 + && SH_MERGE_ARCH_SET (op->arch, arch_op32)) + goto fail; + + if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch)) + goto fail; + for (n = 0; n < max_n; n++) + { + int i = op->nibbles[n]; + + if (i < 16) + { + if (nibs[n] == i) + continue; + goto fail; + } + switch (i) + { + case BRANCH_8: + imm = (nibs[2] << 4) | (nibs[3]); + if (imm & 0x80) + imm |= ~0xff; + imm = ((char) imm) * 2 + 4; + goto ok; + case BRANCH_12: + imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]); + if (imm & 0x800) + imm |= ~0xfff; + imm = imm * 2 + 4; + goto ok; + case IMM0_3c: + if (nibs[3] & 0x8) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3s: + if (!(nibs[3] & 0x8)) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3Uc: + if (nibs[2] & 0x8) + goto fail; + imm = nibs[2] & 0x7; + break; + case IMM0_3Us: + if (!(nibs[2] & 0x8)) + goto fail; + imm = nibs[2] & 0x7; + break; + case DISP0_12: + case DISP1_12: + disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7]; + has_disp = 1; + goto ok; + case DISP0_12BY2: + case DISP1_12BY2: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1; + relmask = ~(bfd_vma) 1; + has_disp = 1; + goto ok; + case DISP0_12BY4: + case DISP1_12BY4: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2; + relmask = ~(bfd_vma) 3; + has_disp = 1; + goto ok; + case DISP0_12BY8: + case DISP1_12BY8: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3; + relmask = ~(bfd_vma) 7; + has_disp = 1; + goto ok; + case IMM0_20_4: + break; + case IMM0_20: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + if (imm & 0x80000) + imm -= 0x100000; + goto ok; + case IMM0_20BY8: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + imm <<= 8; + if (imm & 0x8000000) + imm -= 0x10000000; + goto ok; + case IMM0_4: + case IMM1_4: + imm = nibs[3]; + goto ok; + case IMM0_4BY2: + case IMM1_4BY2: + imm = nibs[3] << 1; + goto ok; + case IMM0_4BY4: + case IMM1_4BY4: + imm = nibs[3] << 2; + goto ok; + case IMM0_8: + case IMM1_8: + imm = (nibs[2] << 4) | nibs[3]; + disp = imm; + has_disp = 1; + if (imm & 0x80) + imm -= 0x100; + goto ok; + case PCRELIMM_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + relmask = ~(bfd_vma) 1; + goto ok; + case PCRELIMM_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + relmask = ~(bfd_vma) 3; + goto ok; + case IMM0_8BY2: + case IMM1_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + goto ok; + case IMM0_8BY4: + case IMM1_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + goto ok; + case REG_N_D: + if ((nibs[n] & 1) != 0) + goto fail; + /* fall through */ + case REG_N: + rn = nibs[n]; + break; + case REG_M: + rm = nibs[n]; + break; + case REG_N_B01: + if ((nibs[n] & 0x3) != 1 /* binary 01 */) + goto fail; + rn = (nibs[n] & 0xc) >> 2; + break; + case REG_NM: + rn = (nibs[n] & 0xc) >> 2; + rm = (nibs[n] & 0x3); + break; + case REG_B: + rb = nibs[n] & 0x07; + break; + case SDT_REG_N: + /* sh-dsp: single data transfer. */ + rn = nibs[n]; + if ((rn & 0xc) != 4) + goto fail; + rn = rn & 0x3; + rn |= (!(rn & 2)) << 2; + break; + case PPI: + case REPEAT: + goto fail; + default: + abort (); + } + } + + ok: + /* sh2a has D_REG but not X_REG. We don't know the pattern + doesn't match unless we check the output args to see if they + make sense. */ + if (target_arch == arch_sh2a + && ((op->arg[0] == DX_REG_M && (rm & 1) != 0) + || (op->arg[1] == DX_REG_N && (rn & 1) != 0))) + goto fail; + + fprintf_fn (stream, "%s\t", op->name); + disp_pc = 0; + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case A_IMM: + fprintf_fn (stream, "#%d", imm); + break; + case A_R0: + fprintf_fn (stream, "r0"); + break; + case A_REG_N: + fprintf_fn (stream, "r%d", rn); + break; + case A_INC_N: + case AS_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case A_DEC_N: + case AS_DEC_N: + fprintf_fn (stream, "@-r%d", rn); + break; + case A_IND_N: + case AS_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_DISP_REG_N: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn); + break; + case AS_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case A_REG_M: + fprintf_fn (stream, "r%d", rm); + break; + case A_INC_M: + fprintf_fn (stream, "@r%d+", rm); + break; + case A_DEC_M: + fprintf_fn (stream, "@-r%d", rm); + break; + case A_IND_M: + fprintf_fn (stream, "@r%d", rm); + break; + case A_DISP_REG_M: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm); + break; + case A_REG_B: + fprintf_fn (stream, "r%d_bank", rb); + break; + case A_DISP_PC: + disp_pc = 1; + disp_pc_addr = imm + 4 + (memaddr & relmask); + (*info->print_address_func) (disp_pc_addr, info); + break; + case A_IND_R0_REG_N: + fprintf_fn (stream, "@(r0,r%d)", rn); + break; + case A_IND_R0_REG_M: + fprintf_fn (stream, "@(r0,r%d)", rm); + break; + case A_DISP_GBR: + fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm); + break; + case A_TBR: + fprintf_fn (stream, "tbr"); + break; + case A_DISP2_TBR: + fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm); + break; + case A_INC_R15: + fprintf_fn (stream, "@r15+"); + break; + case A_DEC_R15: + fprintf_fn (stream, "@-r15"); + break; + case A_R0_GBR: + fprintf_fn (stream, "@(r0,gbr)"); + break; + case A_BDISP12: + case A_BDISP8: + { + bfd_vma addr; + addr = imm + memaddr; + (*info->print_address_func) (addr, info); + } + break; + case A_SR: + fprintf_fn (stream, "sr"); + break; + case A_GBR: + fprintf_fn (stream, "gbr"); + break; + case A_VBR: + fprintf_fn (stream, "vbr"); + break; + case A_DSR: + fprintf_fn (stream, "dsr"); + break; + case A_MOD: + fprintf_fn (stream, "mod"); + break; + case A_RE: + fprintf_fn (stream, "re"); + break; + case A_RS: + fprintf_fn (stream, "rs"); + break; + case A_A0: + fprintf_fn (stream, "a0"); + break; + case A_X0: + fprintf_fn (stream, "x0"); + break; + case A_X1: + fprintf_fn (stream, "x1"); + break; + case A_Y0: + fprintf_fn (stream, "y0"); + break; + case A_Y1: + fprintf_fn (stream, "y1"); + break; + case DSP_REG_M: + print_dsp_reg (rm, fprintf_fn, stream); + break; + case A_SSR: + fprintf_fn (stream, "ssr"); + break; + case A_SPC: + fprintf_fn (stream, "spc"); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + case A_PR: + fprintf_fn (stream, "pr"); + break; + case A_SGR: + fprintf_fn (stream, "sgr"); + break; + case A_DBR: + fprintf_fn (stream, "dbr"); + break; + case F_REG_N: + fprintf_fn (stream, "fr%d", rn); + break; + case F_REG_M: + fprintf_fn (stream, "fr%d", rm); + break; + case DX_REG_N: + if (rn & 1) + { + fprintf_fn (stream, "xd%d", rn & ~1); + break; + } + case D_REG_N: + fprintf_fn (stream, "dr%d", rn); + break; + case DX_REG_M: + if (rm & 1) + { + fprintf_fn (stream, "xd%d", rm & ~1); + break; + } + case D_REG_M: + fprintf_fn (stream, "dr%d", rm); + break; + case FPSCR_M: + case FPSCR_N: + fprintf_fn (stream, "fpscr"); + break; + case FPUL_M: + case FPUL_N: + fprintf_fn (stream, "fpul"); + break; + case F_FR0: + fprintf_fn (stream, "fr0"); + break; + case V_REG_N: + fprintf_fn (stream, "fv%d", rn * 4); + break; + case V_REG_M: + fprintf_fn (stream, "fv%d", rm * 4); + break; + case XMTRX_M4: + fprintf_fn (stream, "xmtrx"); + break; + default: + abort (); + } + } + +#if 0 + /* This code prints instructions in delay slots on the same line + as the instruction which needs the delay slots. This can be + confusing, since other disassembler don't work this way, and + it means that the instructions are not all in a line. So I + disabled it. Ian. */ + if (!(info->flags & 1) + && (op->name[0] == 'j' + || (op->name[0] == 'b' + && (op->name[1] == 'r' + || op->name[1] == 's')) + || (op->name[0] == 'r' && op->name[1] == 't') + || (op->name[0] == 'b' && op->name[2] == '.'))) + { + info->flags |= 1; + fprintf_fn (stream, "\t(slot "); + print_insn_sh (memaddr + 2, info); + info->flags &= ~1; + fprintf_fn (stream, ")"); + return 4; + } +#endif + + if (disp_pc && strcmp (op->name, "mova") != 0) + { + int size; + bfd_byte bytes[4]; + + if (relmask == ~(bfd_vma) 1) + size = 2; + else + size = 4; + status = info->read_memory_func (disp_pc_addr, bytes, size, info); + if (status == 0) + { + unsigned int val; + + if (size == 2) + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl16 (bytes); + else + val = bfd_getb16 (bytes); + } + else + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl32 (bytes); + else + val = bfd_getb32 (bytes); + } + if ((*info->symbol_at_address_func) (val, info)) + { + fprintf_fn (stream, "\t! "); + (*info->print_address_func) (val, info); + } + else + fprintf_fn (stream, "\t! 0x%x", val); + } + } + + return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2; + fail: + ; + + } + fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]); + return 2; +} diff --git a/qemu/qemu-git/softmmu_defs.h b/qemu/qemu-git/softmmu_defs.h new file mode 100644 index 0000000..e38bb75 --- /dev/null +++ b/qemu/qemu-git/softmmu_defs.h @@ -0,0 +1,22 @@ +#ifndef SOFTMMU_DEFS_H +#define SOFTMMU_DEFS_H + +uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); + +uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx); +void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); + +#endif diff --git a/qemu/qemu-git/softmmu_exec.h b/qemu/qemu-git/softmmu_exec.h new file mode 100644 index 0000000..a43e621 --- /dev/null +++ b/qemu/qemu-git/softmmu_exec.h @@ -0,0 +1,134 @@ +/* Common softmmu definitions and inline routines. */ + +/* XXX: find something cleaner. + * Furthermore, this is false for 64 bits targets + */ +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel +#define ldul_hypv ldl_hypv +#define ldul_executive ldl_executive +#define ldul_supervisor ldl_supervisor + +#include "softmmu_defs.h" + +#define ACCESS_TYPE 0 +#define MEMSUFFIX MMU_MODE0_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX MMU_MODE1_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#if (NB_MMU_MODES >= 3) + +#define ACCESS_TYPE 2 +#define MEMSUFFIX MMU_MODE2_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 3) */ + +#if (NB_MMU_MODES >= 4) + +#define ACCESS_TYPE 3 +#define MEMSUFFIX MMU_MODE3_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 4) */ + +#if (NB_MMU_MODES >= 5) + +#define ACCESS_TYPE 4 +#define MEMSUFFIX MMU_MODE4_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 5) */ + +#if (NB_MMU_MODES > 5) +#error "NB_MMU_MODES > 5 is not supported for now" +#endif /* (NB_MMU_MODES > 5) */ + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE (NB_MMU_MODES) +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) diff --git a/qemu/qemu-git/softmmu_header.h b/qemu/qemu-git/softmmu_header.h new file mode 100644 index 0000000..6a36e01 --- /dev/null +++ b/qemu/qemu-git/softmmu_header.h @@ -0,0 +1,198 @@ +/* + * Software MMU support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#if DATA_SIZE == 8 +#define SUFFIX q +#define USUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define USUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define USUFFIX uw +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define USUFFIX ub +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#else +#error unsupported data size +#endif + +#if ACCESS_TYPE < (NB_MMU_MODES) + +#define CPU_MMU_INDEX ACCESS_TYPE +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == (NB_MMU_MODES) + +#define CPU_MMU_INDEX (cpu_mmu_index(env)) +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == (NB_MMU_MODES + 1) + +#define CPU_MMU_INDEX (cpu_mmu_index(env)) +#define MMUSUFFIX _cmmu + +#else +#error invalid ACCESS_TYPE +#endif + +#if DATA_SIZE == 8 +#define RES_TYPE uint64_t +#else +#define RES_TYPE int +#endif + +#if ACCESS_TYPE == (NB_MMU_MODES + 1) +#define ADDR_READ addr_code +#else +#define ADDR_READ addr_read +#endif + +/* generic load/store macros */ + +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) +{ + int page_index; + RES_TYPE res; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} + +#if DATA_SIZE <= 2 +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) +{ + int res, page_index; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} +#endif + +#if ACCESS_TYPE != (NB_MMU_MODES + 1) + +/* generic store macro */ + +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) +{ + int page_index; + target_ulong addr; + unsigned long physaddr; + int mmu_idx; + + addr = ptr; + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { + glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); + } else { + physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); + } +} + +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ + +#if ACCESS_TYPE != (NB_MMU_MODES + 1) + +#if DATA_SIZE == 8 +static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) +{ + union { + float64 d; + uint64_t i; + } u; + u.i = glue(ldq, MEMSUFFIX)(ptr); + return u.d; +} + +static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) +{ + union { + float64 d; + uint64_t i; + } u; + u.d = v; + glue(stq, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 8 */ + +#if DATA_SIZE == 4 +static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = glue(ldl, MEMSUFFIX)(ptr); + return u.f; +} + +static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = v; + glue(stl, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 4 */ + +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ + +#undef RES_TYPE +#undef DATA_TYPE +#undef DATA_STYPE +#undef SUFFIX +#undef USUFFIX +#undef DATA_SIZE +#undef CPU_MMU_INDEX +#undef MMUSUFFIX +#undef ADDR_READ diff --git a/qemu/qemu-git/softmmu_template.h b/qemu/qemu-git/softmmu_template.h new file mode 100644 index 0000000..0e13153 --- /dev/null +++ b/qemu/qemu-git/softmmu_template.h @@ -0,0 +1,327 @@ +/* + * Software MMU support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#define DATA_SIZE (1 << SHIFT) + +#if DATA_SIZE == 8 +#define SUFFIX q +#define USUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define USUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define USUFFIX uw +#define DATA_TYPE uint16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define USUFFIX ub +#define DATA_TYPE uint8_t +#else +#error unsupported data size +#endif + +#ifdef SOFTMMU_CODE_ACCESS +#define READ_ACCESS_TYPE 2 +#define ADDR_READ addr_code +#else +#define READ_ACCESS_TYPE 0 +#define ADDR_READ addr_read +#endif + +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx, + void *retaddr); +static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, + target_ulong addr, + void *retaddr) +{ + DATA_TYPE res; + int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + env->mem_io_pc = (unsigned long)retaddr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } + + env->mem_io_vaddr = addr; +#if SHIFT <= 2 + res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); +#else +#ifdef TARGET_WORDS_BIGENDIAN + res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32; + res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4); +#else + res = io_mem_read[index][2](io_mem_opaque[index], physaddr); + res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32; +#endif +#endif /* SHIFT > 2 */ + return res; +} + +/* handle all cases except unaligned access which span two pages */ +DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx) +{ + DATA_TYPE res; + int index; + target_ulong tlb_addr; + target_phys_addr_t addend; + void *retaddr; + + /* test if there is match for unaligned or IO access */ + /* XXX: could done more in memory macro in a non portable way */ + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + /* slow unaligned access (it spans two pages or IO) */ + do_unaligned_access: + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, + mmu_idx, retaddr); + } else { + /* unaligned/aligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + } +#endif + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + goto redo; + } + return res; +} + +/* handle all unaligned cases */ +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx, + void *retaddr) +{ + DATA_TYPE res, res1, res2; + int index, shift; + target_phys_addr_t addend; + target_ulong tlb_addr, addr1, addr2; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + res = glue(io_read, SUFFIX)(addend, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* slow unaligned access (it spans two pages) */ + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; + res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, + mmu_idx, retaddr); + res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, + mmu_idx, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; +#ifdef TARGET_WORDS_BIGENDIAN + res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); +#else + res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); +#endif + res = (DATA_TYPE)res; + } else { + /* unaligned/aligned access in the same page */ + addend = env->tlb_table[mmu_idx][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend)); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + goto redo; + } + return res; +} + +#ifndef SOFTMMU_CODE_ACCESS + +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx, + void *retaddr); + +static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, + DATA_TYPE val, + target_ulong addr, + void *retaddr) +{ + int index; + index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + physaddr = (physaddr & TARGET_PAGE_MASK) + addr; + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) + && !can_do_io(env)) { + cpu_io_recompile(env, retaddr); + } + + env->mem_io_vaddr = addr; + env->mem_io_pc = (unsigned long)retaddr; +#if SHIFT <= 2 + io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); +#else +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val); +#else + io_mem_write[index][2](io_mem_opaque[index], physaddr, val); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); +#endif +#endif /* SHIFT > 2 */ +} + +void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx) +{ + target_phys_addr_t addend; + target_ulong tlb_addr; + void *retaddr; + int index; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, 1, mmu_idx, retaddr); +#endif + glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, + mmu_idx, retaddr); + } else { + /* aligned/unaligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, 1, mmu_idx, retaddr); + } +#endif + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, 1, mmu_idx, retaddr); +#endif + tlb_fill(addr, 1, mmu_idx, retaddr); + goto redo; + } +} + +/* handles all unaligned cases */ +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, + int mmu_idx, + void *retaddr) +{ + target_phys_addr_t addend; + target_ulong tlb_addr; + int index, i; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + addend = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(addend, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* XXX: not efficient, but simple */ + /* Note: relies on the fact that tlb_fill() does not remove the + * previous page from the TLB cache. */ + for(i = DATA_SIZE - 1; i >= 0; i--) { +#ifdef TARGET_WORDS_BIGENDIAN + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + mmu_idx, retaddr); +#else + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), + mmu_idx, retaddr); +#endif + } + } else { + /* aligned/unaligned access in the same page */ + addend = env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, 1, mmu_idx, retaddr); + goto redo; + } +} + +#endif /* !defined(SOFTMMU_CODE_ACCESS) */ + +#undef READ_ACCESS_TYPE +#undef SHIFT +#undef DATA_TYPE +#undef SUFFIX +#undef USUFFIX +#undef DATA_SIZE +#undef ADDR_READ diff --git a/qemu/qemu-git/sparc-dis.c b/qemu/qemu-git/sparc-dis.c new file mode 100644 index 0000000..83a12ae --- /dev/null +++ b/qemu/qemu-git/sparc-dis.c @@ -0,0 +1,3253 @@ +/* + * These files from binutils are concatenated: + * include/opcode/sparc.h, opcodes/sparc-opc.c, opcodes/sparc-dis.c + */ + +/* include/opcode/sparc.h */ + +/* Definitions for opcode table for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2002, + 2003, 2005 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and + the GNU Binutils. + + GAS/GDB is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS/GDB 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS or GDB; see the file COPYING. If not, + see . */ + +#include +#include "dis-asm.h" + +/* The SPARC opcode table (and other related data) is defined in + the opcodes library in sparc-opc.c. If you change anything here, make + sure you fix up that file, and vice versa. */ + + /* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* List of instruction sets variations. + These values are such that each element is either a superset of a + preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P + returns non-zero. + The values are indices into `sparc_opcode_archs' defined in sparc-opc.c. + Don't change this without updating sparc-opc.c. */ + +enum sparc_opcode_arch_val +{ + SPARC_OPCODE_ARCH_V6 = 0, + SPARC_OPCODE_ARCH_V7, + SPARC_OPCODE_ARCH_V8, + SPARC_OPCODE_ARCH_SPARCLET, + SPARC_OPCODE_ARCH_SPARCLITE, + /* V9 variants must appear last. */ + SPARC_OPCODE_ARCH_V9, + SPARC_OPCODE_ARCH_V9A, /* V9 with ultrasparc additions. */ + SPARC_OPCODE_ARCH_V9B, /* V9 with ultrasparc and cheetah additions. */ + SPARC_OPCODE_ARCH_BAD /* Error return from sparc_opcode_lookup_arch. */ +}; + +/* The highest architecture in the table. */ +#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1) + +/* Given an enum sparc_opcode_arch_val, return the bitmask to use in + insn encoding/decoding. */ +#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch)) + +/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9. */ +#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9) + +/* Table of cpu variants. */ + +typedef struct sparc_opcode_arch +{ + const char *name; + /* Mask of sparc_opcode_arch_val's supported. + EG: For v7 this would be + (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)). + These are short's because sparc_opcode.architecture is. */ + short supported; +} sparc_opcode_arch; + +static const struct sparc_opcode_arch sparc_opcode_archs[]; + +/* Return the bitmask of supported architectures for ARCH. */ +#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) + +/* Non-zero if ARCH1 conflicts with ARCH2. + IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ +#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ + (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH1)) \ + && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH2))) + +/* Structure of an opcode table entry. */ + +typedef struct sparc_opcode +{ + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* This was called "delayed" in versions before the flags. */ + char flags; + short architecture; /* Bitmask of sparc_opcode_arch_val's. */ +} sparc_opcode; + +#define F_DELAYED 1 /* Delayed branch. */ +#define F_ALIAS 2 /* Alias for a "real" instruction. */ +#define F_UNBR 4 /* Unconditional branch. */ +#define F_CONDBR 8 /* Conditional branch. */ +#define F_JSR 16 /* Subroutine call. */ +#define F_FLOAT 32 /* Floating point instruction (not a branch). */ +#define F_FBR 64 /* Floating point branch. */ +/* FIXME: Add F_ANACHRONISTIC flag for v9. */ + +/* All sparc opcodes are 32 bits, except for the `set' instruction (really a + macro), which is 64 bits. It is handled as a special case. + + The match component is a mask saying which bits must match a particular + opcode in order for an instruction to be an instance of that opcode. + + The args component is a string containing one character for each operand of the + instruction. + + Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + X 5 bit unsigned immediate + Y 6 bit unsigned immediate + 3 SIAM mode (3 bits). (v9b) + K MEMBAR mask (7 bits). (v9) + j 10 bit Immediate. (v9) + I 11 bit Immediate. (v9) + i 13 bit Immediate. + n 22 bit immediate. + k 2+14 bit PC relative immediate. (v9) + G 19 bit PC relative immediate. (v9) + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + N Branch predict clear ",pn" (v9) + T Branch predict set ",pt" (v9) + z %icc. (v9) + Z %xcc. (v9) + q Floating point queue. + r Single register that is both rs1 and rd. + O Single register that is both rs2 and rd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + u sparclet coprocessor registers in rd position + U sparclet coprocessor registers in rs1 position + E %ccr. (v9) + s %fprs. (v9) + P %pc. (v9) + W %tick. (v9) + o %asi. (v9) + 6 %fcc0. (v9) + 7 %fcc1. (v9) + 8 %fcc2. (v9) + 9 %fcc3. (v9) + ! Privileged Register in rd (v9) + ? Privileged Register in rs1 (v9) + * Prefetch function constant. (v9) + x OPF field (v9 impdep). + 0 32/64 bit immediate for set or setx (v9) insns + _ Ancillary state register in rd (v9a) + / Ancillary state register in rs1 (v9a) + + The following chars are unused: (note: ,[] are used as punctuation) + [45]. */ + +#define OP2(x) (((x) & 0x7) << 22) /* Op2 field of format2 insns. */ +#define OP3(x) (((x) & 0x3f) << 19) /* Op3 field of format3 insns. */ +#define OP(x) ((unsigned) ((x) & 0x3) << 30) /* Op field of all insns. */ +#define OPF(x) (((x) & 0x1ff) << 5) /* Opf field of float insns. */ +#define OPF_LOW5(x) OPF ((x) & 0x1f) /* V9. */ +#define F3F(x, y, z) (OP (x) | OP3 (y) | OPF (z)) /* Format3 float insns. */ +#define F3I(x) (((x) & 0x1) << 13) /* Immediate field of format 3 insns. */ +#define F2(x, y) (OP (x) | OP2(y)) /* Format 2 insns. */ +#define F3(x, y, z) (OP (x) | OP3(y) | F3I(z)) /* Format3 insns. */ +#define F1(x) (OP (x)) +#define DISP30(x) ((x) & 0x3fffffff) +#define ASI(x) (((x) & 0xff) << 5) /* Asi field of format3 insns. */ +#define RS2(x) ((x) & 0x1f) /* Rs2 field. */ +#define SIMM13(x) ((x) & 0x1fff) /* Simm13 field. */ +#define RD(x) (((x) & 0x1f) << 25) /* Destination register field. */ +#define RS1(x) (((x) & 0x1f) << 14) /* Rs1 field. */ +#define ASI_RS2(x) (SIMM13 (x)) +#define MEMBAR(x) ((x) & 0x7f) +#define SLCPOP(x) (((x) & 0x7f) << 6) /* Sparclet cpop. */ + +#define ANNUL (1 << 29) +#define BPRED (1 << 19) /* V9. */ +#define IMMED F3I (1) +#define RD_G0 RD (~0) +#define RS1_G0 RS1 (~0) +#define RS2_G0 RS2 (~0) + +static const struct sparc_opcode sparc_opcodes[]; + +static const char *sparc_decode_asi_v8 (int); +static const char *sparc_decode_asi_v9 (int); +static const char *sparc_decode_membar (int); +static const char *sparc_decode_prefetch (int); +static const char *sparc_decode_sparclet_cpreg (int); + +/* Local Variables: + fill-column: 131 + comment-column: 0 + End: */ + +/* opcodes/sparc-opc.c */ + +/* Table of opcodes for the sparc. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of the BFD library. + + BFD is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + BFD 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with this software; see the file COPYING. If not, + see . */ + +/* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* Some defines to make life easy. */ +#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) +#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) +#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) +#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) +#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) +#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) +#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) +#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B) + +/* Bit masks of architectures supporting the insn. */ + +#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* v6 insns not supported on the sparclet. */ +#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* Although not all insns are implemented in hardware, sparclite is defined + to be a superset of v8. Unimplemented insns trap and are then theoretically + implemented in software. + It's not clear that the same is true for sparclet, although the docs + suggest it is. Rather than complicating things, the sparclet assembler + recognizes all v8 insns. */ +#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \ + | MASK_V9 | MASK_V9A | MASK_V9B) +#define sparclet (MASK_SPARCLET) +#define sparclite (MASK_SPARCLITE) +#define v9 (MASK_V9 | MASK_V9A | MASK_V9B) +#define v9a (MASK_V9A | MASK_V9B) +#define v9b (MASK_V9B) +/* v6 insns not supported by v9. */ +#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLET | MASK_SPARCLITE) +/* v9a instructions which would appear to be aliases to v9's impdep's + otherwise. */ +#define v9notv9a (MASK_V9) + +/* Table of opcode architectures. + The order is defined in opcode/sparc.h. */ + +static const struct sparc_opcode_arch sparc_opcode_archs[] = +{ + { "v6", MASK_V6 }, + { "v7", MASK_V6 | MASK_V7 }, + { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, + { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, + { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, + /* ??? Don't some v8 privileged insns conflict with v9? */ + { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, + /* v9 with ultrasparc additions */ + { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, + /* v9 with cheetah additions */ + { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B }, + { NULL, 0 } +}; + +/* Branch condition field. */ +#define COND(x) (((x) & 0xf) << 25) + +/* v9: Move (MOVcc and FMOVcc) condition field. */ +#define MCOND(x,i_or_f) ((((i_or_f) & 1) << 18) | (((x) >> 11) & (0xf << 14))) /* v9 */ + +/* v9: Move register (MOVRcc and FMOVRcc) condition field. */ +#define RCOND(x) (((x) & 0x7) << 10) /* v9 */ + +#define CONDA (COND (0x8)) +#define CONDCC (COND (0xd)) +#define CONDCS (COND (0x5)) +#define CONDE (COND (0x1)) +#define CONDG (COND (0xa)) +#define CONDGE (COND (0xb)) +#define CONDGU (COND (0xc)) +#define CONDL (COND (0x3)) +#define CONDLE (COND (0x2)) +#define CONDLEU (COND (0x4)) +#define CONDN (COND (0x0)) +#define CONDNE (COND (0x9)) +#define CONDNEG (COND (0x6)) +#define CONDPOS (COND (0xe)) +#define CONDVC (COND (0xf)) +#define CONDVS (COND (0x7)) + +#define CONDNZ CONDNE +#define CONDZ CONDE +#define CONDGEU CONDCC +#define CONDLU CONDCS + +#define FCONDA (COND (0x8)) +#define FCONDE (COND (0x9)) +#define FCONDG (COND (0x6)) +#define FCONDGE (COND (0xb)) +#define FCONDL (COND (0x4)) +#define FCONDLE (COND (0xd)) +#define FCONDLG (COND (0x2)) +#define FCONDN (COND (0x0)) +#define FCONDNE (COND (0x1)) +#define FCONDO (COND (0xf)) +#define FCONDU (COND (0x7)) +#define FCONDUE (COND (0xa)) +#define FCONDUG (COND (0x5)) +#define FCONDUGE (COND (0xc)) +#define FCONDUL (COND (0x3)) +#define FCONDULE (COND (0xe)) + +#define FCONDNZ FCONDNE +#define FCONDZ FCONDE + +#define ICC (0) /* v9 */ +#define XCC (1 << 12) /* v9 */ +#define FCC(x) (((x) & 0x3) << 11) /* v9 */ +#define FBFCC(x) (((x) & 0x3) << 20) /* v9 */ + +/* The order of the opcodes in the table is significant: + + * The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +/* Entries for commutative arithmetic operations. */ +/* ??? More entries can make use of this. */ +#define COMMUTEOP(opcode, op3, arch_mask) \ +{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } + +static const struct sparc_opcode sparc_opcodes[] = { + +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */ + +/* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the + 'ld' pseudo-op in v9. */ +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */ +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */ + +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */ + +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ + +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ + +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */ + +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */ +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */ + +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ + +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ + +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */ +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */ + +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */ +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */ + +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 }, +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */ +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */ +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */ +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 }, +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ + +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ + +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */ + +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ + +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 }, +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ + +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */ +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */ + +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */ +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 }, +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */ + +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */ + +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ + +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */ +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */ + +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ + +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 }, +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */ +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 }, +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */ +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */ + +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 }, +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */ +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */ + +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ + +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */ + +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ + +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */ +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */ + +{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, +{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 }, + +{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ +{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */ + +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 }, + +{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "allclean", F3(2, 0x31, 0)|RD(2), F3(~2, ~0x31, ~0)|RD(~2)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "otherw", F3(2, 0x31, 0)|RD(3), F3(~2, ~0x31, ~0)|RD(~3)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "normalw", F3(2, 0x31, 0)|RD(4), F3(~2, ~0x31, ~0)|RD(~4)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "invalw", F3(2, 0x31, 0)|RD(5), F3(~2, ~0x31, ~0)|RD(~5)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, + +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 }, +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 }, + +/* IFLUSH was renamed to FLUSH in v8. */ +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 }, + +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 }, +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 }, +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 }, + +{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 }, + +{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 }, +{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 }, + +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */ +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */ + +{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, + +{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, + +{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, + +{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite }, +{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite }, + +{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite }, +{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite }, + +{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 }, +{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 }, + +{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ +{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ + +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */ + +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */ + +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */ +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */ + +{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, + +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ +{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ + +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */ +{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */ +{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */ +{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ + +{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */ +{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */ +{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */ +{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */ +{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */ +{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */ + +{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */ +{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */ +{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */ +{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */ +{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */ +{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */ +{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */ +{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */ +{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */ +{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */ +{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */ +{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */ +{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */ +{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */ +{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */ +{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */ +{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */ +{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */ + +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */ +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ +{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */ +{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */ +{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */ +{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */ +{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */ +{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */ +{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */ + +{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ + +{ "rdhpr", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|SIMM13(~0), "$,d", 0, v9 }, /* rdhpr %hpriv,r */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0), "1,2,%", 0, v9 }, /* wrhpr r1,r2,%hpriv */ +{ "wrhpr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|SIMM13(~0), "1,%", 0, v9 }, /* wrhpr r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "1,i,%", 0, v9 }, /* wrhpr r1,i,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "i,1,%", F_ALIAS, v9 }, /* wrhpr i,r1,%hpriv */ +{ "wrhpr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RS1(~0), "i,%", 0, v9 }, /* wrhpr i,%hpriv */ + +/* ??? This group seems wrong. A three operand move? */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */ + +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ +{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */ +{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */ +{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */ + +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ + +{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, + +{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ +{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ + +/* This is not a commutative instruction. */ +{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, + +{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ +{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ + +{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ +{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ + +{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, + +{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, + +{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, +{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, + +{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, +{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, + +{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, + +{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, + +{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ +{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */ +{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ +{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */ +{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */ +{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */ +{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ +{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */ + +{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ +{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ + +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */ + +{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, + +{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, +{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, + +{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, +{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, + +{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, + +{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 }, + +{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 }, +{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 }, + +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 }, + + +/* Conditional instructions. + + Because this part of the table was such a mess earlier, I have + macrofied it so that all the branches and traps are generated from + a single-line description of each condition value. John Gilmore. */ + +/* Define branches -- one annulled, one without, etc. */ +#define br(opcode, mask, lose, flags) \ + { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \ + { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 } + +#define brx(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), "Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), ",T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a,T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20), ANNUL|BPRED|(lose), ",N Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|ANNUL, BPRED|(lose), ",a,N Z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), "z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), ",T z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a,T z,G", (flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose)|(2<<20), ",N z,G", (flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose)|(2<<20), ",a,N z,G", (flags), v9 } + +/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ +#define tr(opcode, mask, lose, flags) \ + { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \ + { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \ + { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \ + { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ + +/* v9: We must put `brx' before `br', to ensure that we never match something + v9: against an expression unless it is an expression. Otherwise, we end + v9: up with undefined symbol tables entries, because they get added, but + v9: are not deleted if the pattern fails to match. */ + +/* Define both branches and traps based on condition mask */ +#define cond(bop, top, mask, flags) \ + brx(bop, F2(0, 1)|(mask), F2(~0, ~1)|((~mask)&COND(~0)), F_DELAYED|(flags)), /* v9 */ \ + br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \ + tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), ((flags) & ~(F_UNBR|F_CONDBR))) + +/* Define all the conditions, all the branches, all the traps. */ + +/* Standard branch, trap mnemonics */ +cond ("b", "ta", CONDA, F_UNBR), +/* Alternative form (just for assembly, not for disassembly) */ +cond ("ba", "t", CONDA, F_UNBR|F_ALIAS), + +cond ("bcc", "tcc", CONDCC, F_CONDBR), +cond ("bcs", "tcs", CONDCS, F_CONDBR), +cond ("be", "te", CONDE, F_CONDBR), +cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS), +cond ("bg", "tg", CONDG, F_CONDBR), +cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), +cond ("bge", "tge", CONDGE, F_CONDBR), +cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ +cond ("bgu", "tgu", CONDGU, F_CONDBR), +cond ("bl", "tl", CONDL, F_CONDBR), +cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), +cond ("ble", "tle", CONDLE, F_CONDBR), +cond ("bleu", "tleu", CONDLEU, F_CONDBR), +cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ +cond ("bn", "tn", CONDN, F_CONDBR), +cond ("bne", "tne", CONDNE, F_CONDBR), +cond ("bneg", "tneg", CONDNEG, F_CONDBR), +cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */ +cond ("bpos", "tpos", CONDPOS, F_CONDBR), +cond ("bvc", "tvc", CONDVC, F_CONDBR), +cond ("bvs", "tvs", CONDVS, F_CONDBR), +cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ + +#undef cond +#undef br +#undef brr /* v9 */ +#undef tr + +#define brr(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|BPRED, ANNUL|(lose), "1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose), ",T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a,T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose), ",N 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose), ",a,N 1,k", F_DELAYED|(flags), v9 } + +#define condr(bop, mask, flags) /* v9 */ \ + brr(bop, F2(0, 3)|COND(mask), F2(~0, ~3)|COND(~(mask)), (flags)) /* v9 */ + +/* v9 */ condr("brnz", 0x5, F_CONDBR), +/* v9 */ condr("brz", 0x1, F_CONDBR), +/* v9 */ condr("brgez", 0x7, F_CONDBR), +/* v9 */ condr("brlz", 0x3, F_CONDBR), +/* v9 */ condr("brlez", 0x2, F_CONDBR), +/* v9 */ condr("brgz", 0x6, F_CONDBR), + +#undef condr /* v9 */ +#undef brr /* v9 */ + +#define movr(opcode, mask, flags) /* v9 */ \ + { opcode, F3(2, 0x2f, 0)|RCOND(mask), F3(~2, ~0x2f, ~0)|RCOND(~(mask)), "1,2,d", (flags), v9 }, \ + { opcode, F3(2, 0x2f, 1)|RCOND(mask), F3(~2, ~0x2f, ~1)|RCOND(~(mask)), "1,j,d", (flags), v9 } + +#define fmrrs(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,f,g", (flags) | F_FLOAT, v9 } +#define fmrrd(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,B,H", (flags) | F_FLOAT, v9 } +#define fmrrq(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,R,J", (flags) | F_FLOAT, v9 } + +#define fmovrs(mop, mask, flags) /* v9 */ \ + fmrrs(mop, F3(2, 0x35, 0)|OPF_LOW5(5)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~5)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrd(mop, mask, flags) /* v9 */ \ + fmrrd(mop, F3(2, 0x35, 0)|OPF_LOW5(6)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~6)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrq(mop, mask, flags) /* v9 */ \ + fmrrq(mop, F3(2, 0x35, 0)|OPF_LOW5(7)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~7)|RCOND(~(mask)), (flags)) /* v9 */ + +/* v9 */ movr("movrne", 0x5, 0), +/* v9 */ movr("movre", 0x1, 0), +/* v9 */ movr("movrgez", 0x7, 0), +/* v9 */ movr("movrlz", 0x3, 0), +/* v9 */ movr("movrlez", 0x2, 0), +/* v9 */ movr("movrgz", 0x6, 0), +/* v9 */ movr("movrnz", 0x5, F_ALIAS), +/* v9 */ movr("movrz", 0x1, F_ALIAS), + +/* v9 */ fmovrs("fmovrsne", 0x5, 0), +/* v9 */ fmovrs("fmovrse", 0x1, 0), +/* v9 */ fmovrs("fmovrsgez", 0x7, 0), +/* v9 */ fmovrs("fmovrslz", 0x3, 0), +/* v9 */ fmovrs("fmovrslez", 0x2, 0), +/* v9 */ fmovrs("fmovrsgz", 0x6, 0), +/* v9 */ fmovrs("fmovrsnz", 0x5, F_ALIAS), +/* v9 */ fmovrs("fmovrsz", 0x1, F_ALIAS), + +/* v9 */ fmovrd("fmovrdne", 0x5, 0), +/* v9 */ fmovrd("fmovrde", 0x1, 0), +/* v9 */ fmovrd("fmovrdgez", 0x7, 0), +/* v9 */ fmovrd("fmovrdlz", 0x3, 0), +/* v9 */ fmovrd("fmovrdlez", 0x2, 0), +/* v9 */ fmovrd("fmovrdgz", 0x6, 0), +/* v9 */ fmovrd("fmovrdnz", 0x5, F_ALIAS), +/* v9 */ fmovrd("fmovrdz", 0x1, F_ALIAS), + +/* v9 */ fmovrq("fmovrqne", 0x5, 0), +/* v9 */ fmovrq("fmovrqe", 0x1, 0), +/* v9 */ fmovrq("fmovrqgez", 0x7, 0), +/* v9 */ fmovrq("fmovrqlz", 0x3, 0), +/* v9 */ fmovrq("fmovrqlez", 0x2, 0), +/* v9 */ fmovrq("fmovrqgz", 0x6, 0), +/* v9 */ fmovrq("fmovrqnz", 0x5, F_ALIAS), +/* v9 */ fmovrq("fmovrqz", 0x1, F_ALIAS), + +#undef movr /* v9 */ +#undef fmovr /* v9 */ +#undef fmrr /* v9 */ + +#define movicc(opcode, cond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|XCC|(1<<11), "z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|XCC|(1<<11), "z,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|(1<<11), "Z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|(1<<11), "Z,I,d", flags, v9 } + +#define movfcc(opcode, fcond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~0), "6,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~1), "6,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~0), "7,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~1), "7,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~0), "8,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~1), "8,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~0), "9,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~1), "9,I,d", flags, v9 } + +#define movcc(opcode, cond, fcond, flags) /* v9 */ \ + movfcc (opcode, fcond, flags), /* v9 */ \ + movicc (opcode, cond, flags) /* v9 */ + +/* v9 */ movcc ("mova", CONDA, FCONDA, 0), +/* v9 */ movicc ("movcc", CONDCC, 0), +/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS), +/* v9 */ movicc ("movcs", CONDCS, 0), +/* v9 */ movicc ("movlu", CONDLU, F_ALIAS), +/* v9 */ movcc ("move", CONDE, FCONDE, 0), +/* v9 */ movcc ("movg", CONDG, FCONDG, 0), +/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0), +/* v9 */ movicc ("movgu", CONDGU, 0), +/* v9 */ movcc ("movl", CONDL, FCONDL, 0), +/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0), +/* v9 */ movicc ("movleu", CONDLEU, 0), +/* v9 */ movfcc ("movlg", FCONDLG, 0), +/* v9 */ movcc ("movn", CONDN, FCONDN, 0), +/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0), +/* v9 */ movicc ("movneg", CONDNEG, 0), +/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ movfcc ("movo", FCONDO, 0), +/* v9 */ movicc ("movpos", CONDPOS, 0), +/* v9 */ movfcc ("movu", FCONDU, 0), +/* v9 */ movfcc ("movue", FCONDUE, 0), +/* v9 */ movfcc ("movug", FCONDUG, 0), +/* v9 */ movfcc ("movuge", FCONDUGE, 0), +/* v9 */ movfcc ("movul", FCONDUL, 0), +/* v9 */ movfcc ("movule", FCONDULE, 0), +/* v9 */ movicc ("movvc", CONDVC, 0), +/* v9 */ movicc ("movvs", CONDVS, 0), +/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS), + +#undef movicc /* v9 */ +#undef movfcc /* v9 */ +#undef movcc /* v9 */ + +#define FM_SF 1 /* v9 - values for fpsize */ +#define FM_DF 2 /* v9 */ +#define FM_QF 3 /* v9 */ + +#define fmoviccx(opcode, fpsize, args, cond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags, v9 } + +#define fmovfccx(opcode, fpsize, args, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags, v9 } + +/* FIXME: use fmovicc/fmovfcc? */ /* v9 */ +#define fmovccx(opcode, fpsize, args, cond, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags | F_FLOAT, v9 } + +#define fmovicc(suffix, cond, flags) /* v9 */ \ +fmoviccx("fmovd" suffix, FM_DF, "B,H", cond, flags), \ +fmoviccx("fmovq" suffix, FM_QF, "R,J", cond, flags), \ +fmoviccx("fmovs" suffix, FM_SF, "f,g", cond, flags) + +#define fmovfcc(suffix, fcond, flags) /* v9 */ \ +fmovfccx("fmovd" suffix, FM_DF, "B,H", fcond, flags), \ +fmovfccx("fmovq" suffix, FM_QF, "R,J", fcond, flags), \ +fmovfccx("fmovs" suffix, FM_SF, "f,g", fcond, flags) + +#define fmovcc(suffix, cond, fcond, flags) /* v9 */ \ +fmovccx("fmovd" suffix, FM_DF, "B,H", cond, fcond, flags), \ +fmovccx("fmovq" suffix, FM_QF, "R,J", cond, fcond, flags), \ +fmovccx("fmovs" suffix, FM_SF, "f,g", cond, fcond, flags) + +/* v9 */ fmovcc ("a", CONDA, FCONDA, 0), +/* v9 */ fmovicc ("cc", CONDCC, 0), +/* v9 */ fmovicc ("cs", CONDCS, 0), +/* v9 */ fmovcc ("e", CONDE, FCONDE, 0), +/* v9 */ fmovcc ("g", CONDG, FCONDG, 0), +/* v9 */ fmovcc ("ge", CONDGE, FCONDGE, 0), +/* v9 */ fmovicc ("geu", CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("gu", CONDGU, 0), +/* v9 */ fmovcc ("l", CONDL, FCONDL, 0), +/* v9 */ fmovcc ("le", CONDLE, FCONDLE, 0), +/* v9 */ fmovicc ("leu", CONDLEU, 0), +/* v9 */ fmovfcc ("lg", FCONDLG, 0), +/* v9 */ fmovicc ("lu", CONDLU, F_ALIAS), +/* v9 */ fmovcc ("n", CONDN, FCONDN, 0), +/* v9 */ fmovcc ("ne", CONDNE, FCONDNE, 0), +/* v9 */ fmovicc ("neg", CONDNEG, 0), +/* v9 */ fmovcc ("nz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovfcc ("o", FCONDO, 0), +/* v9 */ fmovicc ("pos", CONDPOS, 0), +/* v9 */ fmovfcc ("u", FCONDU, 0), +/* v9 */ fmovfcc ("ue", FCONDUE, 0), +/* v9 */ fmovfcc ("ug", FCONDUG, 0), +/* v9 */ fmovfcc ("uge", FCONDUGE, 0), +/* v9 */ fmovfcc ("ul", FCONDUL, 0), +/* v9 */ fmovfcc ("ule", FCONDULE, 0), +/* v9 */ fmovicc ("vc", CONDVC, 0), +/* v9 */ fmovicc ("vs", CONDVS, 0), +/* v9 */ fmovcc ("z", CONDZ, FCONDZ, F_ALIAS), + +#undef fmoviccx /* v9 */ +#undef fmovfccx /* v9 */ +#undef fmovccx /* v9 */ +#undef fmovicc /* v9 */ +#undef fmovfcc /* v9 */ +#undef fmovcc /* v9 */ +#undef FM_DF /* v9 */ +#undef FM_QF /* v9 */ +#undef FM_SF /* v9 */ + +/* Coprocessor branches. */ +#define CBR(opcode, mask, lose, flags, arch) \ + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED, arch }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED, arch } + +/* Floating point branches. */ +#define FBR(opcode, mask, lose, flags) \ + { opcode, (mask), ANNUL | (lose), "l", flags | F_DELAYED | F_FBR, v6 }, \ + { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED | F_FBR, v6 } + +/* V9 extended floating point branches. */ +#define FBRX(opcode, mask, lose, flags) /* v9 */ \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a,T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask), ANNUL|BPRED|FBFCC(~0)|(lose), ",N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|ANNUL, BPRED|FBFCC(~0)|(lose), ",a,N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), "7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), ",T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a,T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask), ANNUL|BPRED|FBFCC(~1)|(lose), ",N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|ANNUL, BPRED|FBFCC(~1)|(lose), ",a,N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), "8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), ",T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a,T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask), ANNUL|BPRED|FBFCC(~2)|(lose), ",N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|ANNUL, BPRED|FBFCC(~2)|(lose), ",a,N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), "9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), ",T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 } + +/* v9: We must put `FBRX' before `FBR', to ensure that we never match + v9: something against an expression unless it is an expression. Otherwise, + v9: we end up with undefined symbol tables entries, because they get added, + v9: but are not deleted if the pattern fails to match. */ + +#define CONDFC(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet) + +#define CONDFCL(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6) + +#define CONDF(fop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) + +CONDFC ("fb", "cb", 0x8, F_UNBR), +CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS), +CONDFC ("fbe", "cb0", 0x9, F_CONDBR), +CONDF ("fbz", 0x9, F_CONDBR|F_ALIAS), +CONDFC ("fbg", "cb2", 0x6, F_CONDBR), +CONDFC ("fbge", "cb02", 0xb, F_CONDBR), +CONDFC ("fbl", "cb1", 0x4, F_CONDBR), +CONDFC ("fble", "cb01", 0xd, F_CONDBR), +CONDFC ("fblg", "cb12", 0x2, F_CONDBR), +CONDFCL ("fbn", "cbn", 0x0, F_UNBR), +CONDFC ("fbne", "cb123", 0x1, F_CONDBR), +CONDF ("fbnz", 0x1, F_CONDBR|F_ALIAS), +CONDFC ("fbo", "cb012", 0xf, F_CONDBR), +CONDFC ("fbu", "cb3", 0x7, F_CONDBR), +CONDFC ("fbue", "cb03", 0xa, F_CONDBR), +CONDFC ("fbug", "cb23", 0x5, F_CONDBR), +CONDFC ("fbuge", "cb023", 0xc, F_CONDBR), +CONDFC ("fbul", "cb13", 0x3, F_CONDBR), +CONDFC ("fbule", "cb013", 0xe, F_CONDBR), + +#undef CONDFC +#undef CONDFCL +#undef CONDF +#undef CBR +#undef FBR +#undef FBRX /* v9 */ + +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */ + +{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ + +{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 }, +{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 }, + +{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, + +{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, + +{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, + +{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 }, +{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 }, + +/* This *is* a commutative instruction. */ +{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, +/* This *is* a commutative instruction. */ +{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, +{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, + +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ + +{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ +{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ + +/* FPop1 and FPop2 are not instructions. Don't accept them. */ + +{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, + +{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,H", F_FLOAT, v9 }, +{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,H", F_FLOAT, v9 }, + +{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "B,g", F_FLOAT, v9 }, +{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "B,J", F_FLOAT, v9 }, + +{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, +{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 }, +{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 }, +{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 }, +{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 }, +{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 }, +{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 }, +{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 }, +{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 }, + +{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 }, +{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 }, + +{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 }, +{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 }, +{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 }, + +{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 }, + +{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 }, +{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 }, +{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 }, +{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 }, +{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 }, +{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 }, + +#define CMPFCC(x) (((x)&0x3)<<25) + +{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 }, +{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 }, +{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 }, +{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 }, +{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 }, +{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 }, + +/* These Extended FPop (FIFO) instructions are new in the Fujitsu + MB86934, replacing the CPop instructions from v6 and later + processors. */ + +#define EFPOP1_2(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op)|RS1_G0, args, 0, sparclite } +#define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op), args, 0, sparclite } +#define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0, args, 0, sparclite } + +EFPOP1_2 ("efitod", 0x0c8, "f,H"), +EFPOP1_2 ("efitos", 0x0c4, "f,g"), +EFPOP1_2 ("efdtoi", 0x0d2, "B,g"), +EFPOP1_2 ("efstoi", 0x0d1, "f,g"), +EFPOP1_2 ("efstod", 0x0c9, "f,H"), +EFPOP1_2 ("efdtos", 0x0c6, "B,g"), +EFPOP1_2 ("efmovs", 0x001, "f,g"), +EFPOP1_2 ("efnegs", 0x005, "f,g"), +EFPOP1_2 ("efabss", 0x009, "f,g"), +EFPOP1_2 ("efsqrtd", 0x02a, "B,H"), +EFPOP1_2 ("efsqrts", 0x029, "f,g"), +EFPOP1_3 ("efaddd", 0x042, "v,B,H"), +EFPOP1_3 ("efadds", 0x041, "e,f,g"), +EFPOP1_3 ("efsubd", 0x046, "v,B,H"), +EFPOP1_3 ("efsubs", 0x045, "e,f,g"), +EFPOP1_3 ("efdivd", 0x04e, "v,B,H"), +EFPOP1_3 ("efdivs", 0x04d, "e,f,g"), +EFPOP1_3 ("efmuld", 0x04a, "v,B,H"), +EFPOP1_3 ("efmuls", 0x049, "e,f,g"), +EFPOP1_3 ("efsmuld", 0x069, "e,f,H"), +EFPOP2_2 ("efcmpd", 0x052, "v,B"), +EFPOP2_2 ("efcmped", 0x056, "v,B"), +EFPOP2_2 ("efcmps", 0x051, "e,f"), +EFPOP2_2 ("efcmpes", 0x055, "e,f"), + +#undef EFPOP1_2 +#undef EFPOP1_3 +#undef EFPOP2_2 + +/* These are marked F_ALIAS, so that they won't conflict with sparclite insns + present. Otherwise, the F_ALIAS flag is ignored. */ +{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 }, +{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 }, + +/* sparclet specific insns */ + +COMMUTEOP ("umac", 0x3e, sparclet), +COMMUTEOP ("smac", 0x3f, sparclet), +COMMUTEOP ("umacd", 0x2e, sparclet), +COMMUTEOP ("smacd", 0x2f, sparclet), +COMMUTEOP ("umuld", 0x09, sparclet), +COMMUTEOP ("smuld", 0x0d, sparclet), + +{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet }, +{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet }, + +/* The manual isn't completely accurate on these insns. The `rs2' field is + treated as being 6 bits to account for 6 bit immediates to cpush. It is + assumed that it is intended that bit 5 is 0 when rs2 contains a reg. */ +#define BIT5 (1<<5) +{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet }, +{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet }, +{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet }, +{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet }, +#undef BIT5 + +/* sparclet coprocessor branch insns */ +#define SLCBCC2(opcode, mask, lose) \ + { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR, sparclet }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet } +#define SLCBCC(opcode, mask) \ + SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask))) + +/* cbn,cba can't be defined here because they're defined elsewhere and GAS + requires all mnemonics of the same name to be consecutive. */ +/*SLCBCC("cbn", 0), - already defined */ +SLCBCC("cbe", 1), +SLCBCC("cbf", 2), +SLCBCC("cbef", 3), +SLCBCC("cbr", 4), +SLCBCC("cber", 5), +SLCBCC("cbfr", 6), +SLCBCC("cbefr", 7), +/*SLCBCC("cba", 8), - already defined */ +SLCBCC("cbne", 9), +SLCBCC("cbnf", 10), +SLCBCC("cbnef", 11), +SLCBCC("cbnr", 12), +SLCBCC("cbner", 13), +SLCBCC("cbnfr", 14), +SLCBCC("cbnefr", 15), + +#undef SLCBCC2 +#undef SLCBCC + +{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 }, +{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 }, + +/* v9 synthetic insns */ +{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */ +{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */ +{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */ +{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */ +{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */ + +/* Ultrasparc extensions */ +{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a }, + +/* FIXME: Do we want to mark these as F_FLOAT, or something similar? */ +{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a }, +{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a }, +{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a }, +{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a }, +{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a }, +{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a }, +{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a }, +{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a }, + +{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a }, +{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a }, +{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a }, +{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a }, +{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a }, + +/* Note that the mixing of 32/64 bit regs is intentional. */ +{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a }, +{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a }, +{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a }, +{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a }, +{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a }, +{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a }, +{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a }, + +{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a }, +{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a }, +{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a }, + +{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a }, +{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a }, +{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a }, +{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a }, +{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a }, +{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a }, +{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a }, +{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a }, +{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a }, +{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a }, +{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a }, +{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a }, +{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a }, +{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a }, +{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a }, +{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a }, +{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a }, +{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a }, +{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a }, +{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a }, +{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a }, +{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a }, +{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a }, +{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a }, +{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a }, +{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a }, +{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a }, +{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a }, +{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a }, +{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a }, +{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a }, +{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a }, + +{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a }, +{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a }, +{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a }, +{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a }, +{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a }, +{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a }, +{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a }, +{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a }, + +{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a }, +{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a }, +{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a }, +{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a }, +{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a }, +{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a }, + +{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a }, + +{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a }, +{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a }, +{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a }, + +/* Cheetah instructions */ +{ "edge8n", F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b }, +{ "edge8ln", F3F(2, 0x36, 0x003), F3F(~2, ~0x36, ~0x003), "1,2,d", 0, v9b }, +{ "edge16n", F3F(2, 0x36, 0x005), F3F(~2, ~0x36, ~0x005), "1,2,d", 0, v9b }, +{ "edge16ln", F3F(2, 0x36, 0x007), F3F(~2, ~0x36, ~0x007), "1,2,d", 0, v9b }, +{ "edge32n", F3F(2, 0x36, 0x009), F3F(~2, ~0x36, ~0x009), "1,2,d", 0, v9b }, +{ "edge32ln", F3F(2, 0x36, 0x00b), F3F(~2, ~0x36, ~0x00b), "1,2,d", 0, v9b }, + +{ "bmask", F3F(2, 0x36, 0x019), F3F(~2, ~0x36, ~0x019), "1,2,d", 0, v9b }, +{ "bshuffle", F3F(2, 0x36, 0x04c), F3F(~2, ~0x36, ~0x04c), "v,B,H", 0, v9b }, + +{ "siam", F3F(2, 0x36, 0x081), F3F(~2, ~0x36, ~0x081)|RD_G0|RS1_G0|RS2(~7), "3", 0, v9b }, + +/* More v9 specific insns, these need to come last so they do not clash + with v9a instructions such as "edge8" which looks like impdep1. */ + +#define IMPDEP(name, code) \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,e,f,g", 0, v9notv9a } + +IMPDEP ("impdep1", 0x36), +IMPDEP ("impdep2", 0x37), + +#undef IMPDEP + +}; + +static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); + +/* Utilities for argument parsing. */ + +typedef struct +{ + int value; + const char *name; +} arg; + +/* Look up VALUE in TABLE. */ + +static const char * +lookup_value (const arg *table, int value) +{ + const arg *p; + + for (p = table; p->name; ++p) + if (value == p->value) + return p->name; + + return NULL; +} + +/* Handle ASI's. */ + +static const arg asi_table_v8[] = +{ + { 0x00, "#ASI_M_RES00" }, + { 0x01, "#ASI_M_UNA01" }, + { 0x02, "#ASI_M_MXCC" }, + { 0x03, "#ASI_M_FLUSH_PROBE" }, + { 0x04, "#ASI_M_MMUREGS" }, + { 0x05, "#ASI_M_TLBDIAG" }, + { 0x06, "#ASI_M_DIAGS" }, + { 0x07, "#ASI_M_IODIAG" }, + { 0x08, "#ASI_M_USERTXT" }, + { 0x09, "#ASI_M_KERNELTXT" }, + { 0x0A, "#ASI_M_USERDATA" }, + { 0x0B, "#ASI_M_KERNELDATA" }, + { 0x0C, "#ASI_M_TXTC_TAG" }, + { 0x0D, "#ASI_M_TXTC_DATA" }, + { 0x0E, "#ASI_M_DATAC_TAG" }, + { 0x0F, "#ASI_M_DATAC_DATA" }, + { 0x10, "#ASI_M_FLUSH_PAGE" }, + { 0x11, "#ASI_M_FLUSH_SEG" }, + { 0x12, "#ASI_M_FLUSH_REGION" }, + { 0x13, "#ASI_M_FLUSH_CTX" }, + { 0x14, "#ASI_M_FLUSH_USER" }, + { 0x17, "#ASI_M_BCOPY" }, + { 0x18, "#ASI_M_IFLUSH_PAGE" }, + { 0x19, "#ASI_M_IFLUSH_SEG" }, + { 0x1A, "#ASI_M_IFLUSH_REGION" }, + { 0x1B, "#ASI_M_IFLUSH_CTX" }, + { 0x1C, "#ASI_M_IFLUSH_USER" }, + { 0x1F, "#ASI_M_BFILL" }, + { 0x20, "#ASI_M_BYPASS" }, + { 0x29, "#ASI_M_FBMEM" }, + { 0x2A, "#ASI_M_VMEUS" }, + { 0x2B, "#ASI_M_VMEPS" }, + { 0x2C, "#ASI_M_VMEUT" }, + { 0x2D, "#ASI_M_VMEPT" }, + { 0x2E, "#ASI_M_SBUS" }, + { 0x2F, "#ASI_M_CTL" }, + { 0x31, "#ASI_M_FLUSH_IWHOLE" }, + { 0x36, "#ASI_M_IC_FLCLEAR" }, + { 0x37, "#ASI_M_DC_FLCLEAR" }, + { 0x39, "#ASI_M_DCDR" }, + { 0x40, "#ASI_M_VIKING_TMP1" }, + { 0x41, "#ASI_M_VIKING_TMP2" }, + { 0x4c, "#ASI_M_ACTION" }, + { 0, NULL } +}; + +static const arg asi_table_v9[] = +{ + /* These are in the v9 architecture manual. */ + /* The shorter versions appear first, they're here because Sun's as has them. + Sun's as uses #ASI_P_L instead of #ASI_PL (which appears in the + UltraSPARC architecture manual). */ + { 0x04, "#ASI_N" }, + { 0x0c, "#ASI_N_L" }, + { 0x10, "#ASI_AIUP" }, + { 0x11, "#ASI_AIUS" }, + { 0x18, "#ASI_AIUP_L" }, + { 0x19, "#ASI_AIUS_L" }, + { 0x80, "#ASI_P" }, + { 0x81, "#ASI_S" }, + { 0x82, "#ASI_PNF" }, + { 0x83, "#ASI_SNF" }, + { 0x88, "#ASI_P_L" }, + { 0x89, "#ASI_S_L" }, + { 0x8a, "#ASI_PNF_L" }, + { 0x8b, "#ASI_SNF_L" }, + { 0x04, "#ASI_NUCLEUS" }, + { 0x0c, "#ASI_NUCLEUS_LITTLE" }, + { 0x10, "#ASI_AS_IF_USER_PRIMARY" }, + { 0x11, "#ASI_AS_IF_USER_SECONDARY" }, + { 0x18, "#ASI_AS_IF_USER_PRIMARY_LITTLE" }, + { 0x19, "#ASI_AS_IF_USER_SECONDARY_LITTLE" }, + { 0x80, "#ASI_PRIMARY" }, + { 0x81, "#ASI_SECONDARY" }, + { 0x82, "#ASI_PRIMARY_NOFAULT" }, + { 0x83, "#ASI_SECONDARY_NOFAULT" }, + { 0x88, "#ASI_PRIMARY_LITTLE" }, + { 0x89, "#ASI_SECONDARY_LITTLE" }, + { 0x8a, "#ASI_PRIMARY_NOFAULT_LITTLE" }, + { 0x8b, "#ASI_SECONDARY_NOFAULT_LITTLE" }, + /* These are UltraSPARC extensions. */ + /* FIXME: There are dozens of them. Not sure we want them all. + Most are for kernel building but some are for vis type stuff. */ + { 0, NULL } +}; + +/* Return the name for ASI value VALUE or NULL if not found. */ + +static const char * +sparc_decode_asi_v9 (int value) +{ + return lookup_value (asi_table_v9, value); +} + +static const char * +sparc_decode_asi_v8 (int value) +{ + return lookup_value (asi_table_v8, value); +} + +/* Handle membar masks. */ + +static const arg membar_table[] = +{ + { 0x40, "#Sync" }, + { 0x20, "#MemIssue" }, + { 0x10, "#Lookaside" }, + { 0x08, "#StoreStore" }, + { 0x04, "#LoadStore" }, + { 0x02, "#StoreLoad" }, + { 0x01, "#LoadLoad" }, + { 0, NULL } +}; + +/* Return the name for membar value VALUE or NULL if not found. */ + +static const char * +sparc_decode_membar (int value) +{ + return lookup_value (membar_table, value); +} + +/* Handle prefetch args. */ + +static const arg prefetch_table[] = +{ + { 0, "#n_reads" }, + { 1, "#one_read" }, + { 2, "#n_writes" }, + { 3, "#one_write" }, + { 4, "#page" }, + { 16, "#invalidate" }, + { 0, NULL } +}; + +/* Return the name for prefetch value VALUE or NULL if not found. */ + +static const char * +sparc_decode_prefetch (int value) +{ + return lookup_value (prefetch_table, value); +} + +/* Handle sparclet coprocessor registers. */ + +static const arg sparclet_cpreg_table[] = +{ + { 0, "%ccsr" }, + { 1, "%ccfr" }, + { 2, "%cccrcr" }, + { 3, "%ccpr" }, + { 4, "%ccsr2" }, + { 5, "%cccrr" }, + { 6, "%ccrstr" }, + { 0, NULL } +}; + +/* Return the name for sparclet cpreg value VALUE or NULL if not found. */ + +static const char * +sparc_decode_sparclet_cpreg (int value) +{ + return lookup_value (sparclet_cpreg_table, value); +} + +#undef MASK_V9 + +/* opcodes/sparc-dis.c */ + +/* Print SPARC instructions. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Bitmask of v9 architectures. */ +#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ + | (1 << SPARC_OPCODE_ARCH_V9A) \ + | (1 << SPARC_OPCODE_ARCH_V9B)) +/* 1 if INSN is for v9 only. */ +#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9)) +/* 1 if INSN is for v9. */ +#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0) + +/* The sorted opcode table. */ +static const sparc_opcode **sorted_opcodes; + +/* For faster lookup, after insns are sorted they are hashed. */ +/* ??? I think there is room for even more improvement. */ + +#define HASH_SIZE 256 +/* It is important that we only look at insn code bits as that is how the + opcode table is hashed. OPCODE_BITS is a table of valid bits for each + of the main types (0,1,2,3). */ +static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; +#define HASH_INSN(INSN) \ + ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) +typedef struct sparc_opcode_hash +{ + struct sparc_opcode_hash *next; + const sparc_opcode *opcode; +} sparc_opcode_hash; + +static sparc_opcode_hash *opcode_hash_table[HASH_SIZE]; + +/* Sign-extend a value which is N bits long. */ +#define SEX(value, bits) \ + ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ + >> ((8 * sizeof (int)) - bits) ) + +static const char * const reg_names[] = +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", + "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", + "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", + "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", +/* psr, wim, tbr, fpsr, cpsr are v8 only. */ + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" +}; + +#define freg_names (®_names[4 * 8]) + +/* These are ordered according to there register number in + rdpr and wrpr insns. */ +static const char * const v9_priv_reg_names[] = +{ + "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", + "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", + "wstate", "fq", "gl" + /* "ver" - special cased */ +}; + +/* These are ordered according to there register number in + rdhpr and wrhpr insns. */ +static const char * const v9_hpriv_reg_names[] = +{ + "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver", + "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13", + "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20", + "resv21", "resv22", "resv23", "resv24", "resv25", "resv26", "resv27", + "resv28", "resv29", "resv30", "hstick_cmpr" +}; + +/* These are ordered according to there register number in + rd and wr insns (-16). */ +static const char * const v9a_asr_reg_names[] = +{ + "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint", + "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr" +}; + +/* Macros used to extract instruction fields. Not all fields have + macros defined here, only those which are actually used. */ + +#define X_RD(i) (((i) >> 25) & 0x1f) +#define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_LDST_I(i) (((i) >> 13) & 1) +#define X_ASI(i) (((i) >> 5) & 0xff) +#define X_RS2(i) (((i) >> 0) & 0x1f) +#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) +#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) +#define X_DISP22(i) (((i) >> 0) & 0x3fffff) +#define X_IMM22(i) X_DISP22 (i) +#define X_DISP30(i) (((i) >> 0) & 0x3fffffff) + +/* These are for v9. */ +#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) +#define X_DISP19(i) (((i) >> 0) & 0x7ffff) +#define X_MEMBAR(i) ((i) & 0x7f) + +/* Here is the union which was used to extract instruction fields + before the shift and mask macros were written. + + union sparc_insn + { + unsigned long int code; + struct + { + unsigned int anop:2; + #define op ldst.anop + unsigned int anrd:5; + #define rd ldst.anrd + unsigned int op3:6; + unsigned int anrs1:5; + #define rs1 ldst.anrs1 + unsigned int i:1; + unsigned int anasi:8; + #define asi ldst.anasi + unsigned int anrs2:5; + #define rs2 ldst.anrs2 + #define shcnt rs2 + } ldst; + struct + { + unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; + unsigned int IMM13:13; + #define imm13 IMM13.IMM13 + } IMM13; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; + #define disp22 branch.DISP22 + #define imm22 disp22 + } branch; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int z:1; + unsigned int rcond:3; + unsigned int op2:3; + unsigned int DISP16HI:2; + unsigned int p:1; + unsigned int _rs1:5; + unsigned int DISP16LO:14; + } branch16; + struct + { + unsigned int anop:2; + unsigned int adisp30:30; + #define disp30 call.adisp30 + } call; + }; */ + +/* Nonzero if INSN is the opcode for a delayed branch. */ + +static int +is_delayed_branch (unsigned long insn) +{ + sparc_opcode_hash *op; + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const sparc_opcode *opcode = op->opcode; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + return opcode->flags & F_DELAYED; + } + return 0; +} + +/* extern void qsort (); */ + +/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value + to compare_opcodes. */ +static unsigned int current_arch_mask; + +/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ + +static int +compute_arch_mask (unsigned long mach) +{ + switch (mach) + { + case 0 : + case bfd_mach_sparc : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); + case bfd_mach_sparc_sparclet : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); + case bfd_mach_sparc_sparclite : + case bfd_mach_sparc_sparclite_le : + /* sparclites insns are recognized by default (because that's how + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ + return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + case bfd_mach_sparc_v8plus : + case bfd_mach_sparc_v9 : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); + case bfd_mach_sparc_v8plusa : + case bfd_mach_sparc_v9a : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); + case bfd_mach_sparc_v8plusb : + case bfd_mach_sparc_v9b : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); + } + abort (); +} + +/* Compare opcodes A and B. */ + +static int +compare_opcodes (const void * a, const void * b) +{ + sparc_opcode *op0 = * (sparc_opcode **) a; + sparc_opcode *op1 = * (sparc_opcode **) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; + + /* If one (and only one) insn isn't supported by the current architecture, + prefer the one that is. If neither are supported, but they're both for + the same architecture, continue processing. Otherwise (both unsupported + and for different architectures), prefer lower numbered arch's (fudged + by comparing the bitmasks). */ + if (op0->architecture & current_arch_mask) + { + if (! (op1->architecture & current_arch_mask)) + return -1; + } + else + { + if (op1->architecture & current_arch_mask) + return 1; + else if (op0->architecture != op1->architecture) + return op0->architecture - op1->architecture; + } + + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } + + if (match1 & lose1) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } + + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ + + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); + + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } + + /* Except for aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + i = strcmp (op0->name, op1->name); + if (i) + { + if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ + return i; + else + fprintf (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), + op0->name, op1->name); + } + + /* Fewer arguments are preferred. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) strchr (op0->args, '+'); + char *p1 = (char *) strchr (op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* Put 1,i before i,1. */ + { + int i0 = strncmp (op0->args, "i,1", 3) == 0; + int i1 = strncmp (op1->args, "i,1", 3) == 0; + + if (i0 ^ i1) + return i0 - i1; + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + /* ??? This is no longer true now that we sort a vector of pointers, + not the table itself. */ + return 0; +} + +/* Build a hash table from the opcode table. + OPCODE_TABLE is a sorted list of pointers into the opcode table. */ + +static void +build_hash_table (const sparc_opcode **opcode_table, + sparc_opcode_hash **hash_table, + int num_opcodes) +{ + int i; + int hash_count[HASH_SIZE]; + static sparc_opcode_hash *hash_buf = NULL; + + /* Start at the end of the table and work backwards so that each + chain is sorted. */ + + memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); + memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); + if (hash_buf != NULL) + free (hash_buf); + hash_buf = malloc (sizeof (* hash_buf) * num_opcodes); + for (i = num_opcodes - 1; i >= 0; --i) + { + int hash = HASH_INSN (opcode_table[i]->match); + sparc_opcode_hash *h = &hash_buf[i]; + + h->next = hash_table[hash]; + h->opcode = opcode_table[i]; + hash_table[hash] = h; + ++hash_count[hash]; + } + +#if 0 /* for debugging */ + { + int min_count = num_opcodes, max_count = 0; + int total; + + for (i = 0; i < HASH_SIZE; ++i) + { + if (hash_count[i] < min_count) + min_count = hash_count[i]; + if (hash_count[i] > max_count) + max_count = hash_count[i]; + total += hash_count[i]; + } + + printf ("Opcode hash table stats: min %d, max %d, ave %f\n", + min_count, max_count, (double) total / HASH_SIZE); + } +#endif +} + +/* Print one instruction from MEMADDR on INFO->STREAM. + + We suffix the instruction with a comment that gives the absolute + address involved, as well as its symbolic form, if the instruction + is preceded by a findable `sethi' and it either adds an immediate + displacement to that register, or it is an `add' or `or' instruction + on that register. */ + +int +print_insn_sparc (bfd_vma memaddr, disassemble_info *info) +{ + FILE *stream = info->stream; + bfd_byte buffer[4]; + unsigned long insn; + sparc_opcode_hash *op; + /* Nonzero of opcode table has been initialized. */ + static int opcodes_initialized = 0; + /* bfd mach number of last call. */ + static unsigned long current_mach = 0; + bfd_vma (*getword) (const unsigned char *); + + if (!opcodes_initialized + || info->mach != current_mach) + { + int i; + + current_arch_mask = compute_arch_mask (info->mach); + + if (!opcodes_initialized) + sorted_opcodes = + malloc (sparc_num_opcodes * sizeof (sparc_opcode *)); + /* Reset the sorted table so we can resort it. */ + for (i = 0; i < sparc_num_opcodes; ++i) + sorted_opcodes[i] = &sparc_opcodes[i]; + qsort ((char *) sorted_opcodes, sparc_num_opcodes, + sizeof (sorted_opcodes[0]), compare_opcodes); + + build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); + current_mach = info->mach; + opcodes_initialized = 1; + } + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + /* On SPARClite variants such as DANlite (sparc86x), instructions + are always big-endian even when the machine is in little-endian mode. */ + if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) + getword = bfd_getb32; + else + getword = bfd_getl32; + + insn = getword (buffer); + + info->insn_info_valid = 1; /* We do return this info. */ + info->insn_type = dis_nonbranch; /* Assume non branch insn. */ + info->branch_delay_insns = 0; /* Assume no delay. */ + info->target = 0; /* Assume no target known. */ + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const sparc_opcode *opcode = op->opcode; + + /* If the insn isn't supported by the current architecture, skip it. */ + if (! (opcode->architecture & current_arch_mask)) + continue; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + int imm_ored_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Nonzero means we have an annulled branch. */ + /* int is_annulled = 0; */ /* see FIXME below */ + + /* Do we have an `add' or `or' instruction combining an + immediate with rs1? */ + if (opcode->match == 0x80102000) /* or */ + imm_ored_to_rs1 = 1; + if (opcode->match == 0x80002000) /* add */ + imm_added_to_rs1 = 1; + + if (X_RS1 (insn) != X_RD (insn) + && strchr (opcode->args, 'r') != NULL) + /* Can't do simple format if source and dest are different. */ + continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != NULL) + /* Can't do simple format if source and dest are different. */ + continue; + + (*info->fprintf_func) (stream, opcode->name); + + { + const char *s; + + if (opcode->args[0] != ',') + (*info->fprintf_func) (stream, " "); + + for (s = opcode->args; *s != '\0'; ++s) + { + while (*s == ',') + { + (*info->fprintf_func) (stream, ","); + ++s; + switch (*s) + { + case 'a': + (*info->fprintf_func) (stream, "a"); + /* is_annulled = 1; */ /* see FIXME below */ + ++s; + continue; + case 'N': + (*info->fprintf_func) (stream, "pn"); + ++s; + continue; + + case 'T': + (*info->fprintf_func) (stream, "pt"); + ++s; + continue; + + default: + break; + } + } + + (*info->fprintf_func) (stream, " "); + + switch (*s) + { + case '+': + found_plus = 1; + /* Fall through. */ + + default: + (*info->fprintf_func) (stream, "%c", *s); + break; + + case '#': + (*info->fprintf_func) (stream, "0"); + break; + +#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (X_RS1 (insn)); + break; + + case '2': + case 'O': + reg (X_RS2 (insn)); + break; + + case 'd': + reg (X_RD (insn)); + break; +#undef reg + +#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) +#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) + case 'e': + freg (X_RS1 (insn)); + break; + case 'v': /* Double/even. */ + case 'V': /* Quad/multiple of 4. */ + fregx (X_RS1 (insn)); + break; + + case 'f': + freg (X_RS2 (insn)); + break; + case 'B': /* Double/even. */ + case 'R': /* Quad/multiple of 4. */ + fregx (X_RS2 (insn)); + break; + + case 'g': + freg (X_RD (insn)); + break; + case 'H': /* Double/even. */ + case 'J': /* Quad/multiple of 4. */ + fregx (X_RD (insn)); + break; +#undef freg +#undef fregx + +#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (X_RS1 (insn)); + break; + + case 'c': + creg (X_RS2 (insn)); + break; + + case 'D': + creg (X_RD (insn)); + break; +#undef creg + + case 'h': + (*info->fprintf_func) (stream, "%%hi(%#x)", + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (insn) << 10))); + break; + + case 'i': /* 13 bit immediate. */ + case 'I': /* 11 bit immediate. */ + case 'j': /* 10 bit immediate. */ + { + int imm; + + if (*s == 'i') + imm = X_SIMM (insn, 13); + else if (*s == 'I') + imm = X_SIMM (insn, 11); + else + imm = X_SIMM (insn, 10); + + /* Check to see whether we have a 1+i, and take + note of that fact. + + Note: because of the way we sort the table, + we will be matching 1+i rather than i+1, + so it is OK to assume that i is after +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + (*info->fprintf_func) (stream, "%d", imm); + else + (*info->fprintf_func) (stream, "%#x", imm); + } + break; + + case 'X': /* 5 bit unsigned immediate. */ + case 'Y': /* 6 bit unsigned immediate. */ + { + int imm = X_IMM (insn, *s == 'X' ? 5 : 6); + + if (imm <= 9) + (info->fprintf_func) (stream, "%d", imm); + else + (info->fprintf_func) (stream, "%#x", (unsigned) imm); + } + break; + + case '3': + (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3)); + break; + + case 'K': + { + int mask = X_MEMBAR (insn); + int bit = 0x40, printed_one = 0; + const char *name; + + if (mask == 0) + (info->fprintf_func) (stream, "0"); + else + while (bit) + { + if (mask & bit) + { + if (printed_one) + (info->fprintf_func) (stream, "|"); + name = sparc_decode_membar (bit); + (info->fprintf_func) (stream, "%s", name); + printed_one = 1; + } + bit >>= 1; + } + break; + } + + case 'k': + info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'G': + info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; + (*info->print_address_func) (info->target, info); + break; + + case '6': + case '7': + case '8': + case '9': + (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); + break; + + case 'z': + (*info->fprintf_func) (stream, "%%icc"); + break; + + case 'Z': + (*info->fprintf_func) (stream, "%%xcc"); + break; + + case 'E': + (*info->fprintf_func) (stream, "%%ccr"); + break; + + case 's': + (*info->fprintf_func) (stream, "%%fprs"); + break; + + case 'o': + (*info->fprintf_func) (stream, "%%asi"); + break; + + case 'W': + (*info->fprintf_func) (stream, "%%tick"); + break; + + case 'P': + (*info->fprintf_func) (stream, "%%pc"); + break; + + case '?': + if (X_RS1 (insn) == 31) + (*info->fprintf_func) (stream, "%%ver"); + else if ((unsigned) X_RS1 (insn) < 17) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '!': + if ((unsigned) X_RD (insn) < 17) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '$': + if ((unsigned) X_RS1 (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '%': + if ((unsigned) X_RD (insn) < 32) + (*info->fprintf_func) (stream, "%%%s", + v9_hpriv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '/': + if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RS1 (insn)-16]); + break; + + case '_': + if (X_RD (insn) < 16 || X_RD (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RD (insn)-16]); + break; + + case '*': + { + const char *name = sparc_decode_prefetch (X_RD (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%ld", X_RD (insn)); + break; + } + + case 'M': + (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn)); + break; + + case 'm': + (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn)); + break; + + case 'L': + info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'n': + (*info->fprintf_func) + (stream, "%#x", SEX (X_DISP22 (insn), 22)); + break; + + case 'l': + info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'A': + { + const char *name; + + if ((info->mach == bfd_mach_sparc_v8plusa) || + ((info->mach >= bfd_mach_sparc_v9) && + (info->mach <= bfd_mach_sparc_v9b))) + name = sparc_decode_asi_v9 (X_ASI (insn)); + else + name = sparc_decode_asi_v8 (X_ASI (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn)); + break; + } + + case 'C': + (*info->fprintf_func) (stream, "%%csr"); + break; + + case 'F': + (*info->fprintf_func) (stream, "%%fsr"); + break; + + case 'p': + (*info->fprintf_func) (stream, "%%psr"); + break; + + case 'q': + (*info->fprintf_func) (stream, "%%fq"); + break; + + case 'Q': + (*info->fprintf_func) (stream, "%%cq"); + break; + + case 't': + (*info->fprintf_func) (stream, "%%tbr"); + break; + + case 'w': + (*info->fprintf_func) (stream, "%%wim"); + break; + + case 'x': + (*info->fprintf_func) (stream, "%ld", + ((X_LDST_I (insn) << 8) + + X_ASI (insn))); + break; + + case 'y': + (*info->fprintf_func) (stream, "%%y"); + break; + + case 'u': + case 'U': + { + int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); + const char *name = sparc_decode_sparclet_cpreg (val); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%%cpreg(%d)", val); + break; + } + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_ored_to_rs1 || imm_added_to_rs1) + { + unsigned long prev_insn; + int errcode; + + if (memaddr >= 4) + errcode = + (*info->read_memory_func) + (memaddr - 4, buffer, sizeof (buffer), info); + else + errcode = 1; + + prev_insn = getword (buffer); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as: + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 */ + + if (is_delayed_branch (prev_insn)) + { + if (memaddr >= 8) + errcode = (*info->read_memory_func) + (memaddr - 8, buffer, sizeof (buffer), info); + else + errcode = 1; + + prev_insn = getword (buffer); + } + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn & 0xc1c00000) == 0x01000000 + && X_RD (prev_insn) == X_RS1 (insn)) + { + (*info->fprintf_func) (stream, "\t! "); + info->target = + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (prev_insn) << 10)); + if (imm_added_to_rs1) + info->target += X_SIMM (insn, 13); + else + info->target |= X_SIMM (insn, 13); + (*info->print_address_func) (info->target, info); + info->insn_type = dis_dref; + info->data_size = 4; /* FIXME!!! */ + } + } + } + + if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) + { + /* FIXME -- check is_annulled flag. */ + if (opcode->flags & F_UNBR) + info->insn_type = dis_branch; + if (opcode->flags & F_CONDBR) + info->insn_type = dis_condbranch; + if (opcode->flags & F_JSR) + info->insn_type = dis_jsr; + if (opcode->flags & F_DELAYED) + info->branch_delay_insns = 1; + } + + return sizeof (buffer); + } + } + + info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */ + (*info->fprintf_func) (stream, _("unknown")); + return sizeof (buffer); +} diff --git a/qemu/qemu-git/sparc.ld b/qemu/qemu-git/sparc.ld new file mode 100644 index 0000000..31321be --- /dev/null +++ b/qemu/qemu-git/sparc.ld @@ -0,0 +1,150 @@ +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", + "elf32-sparc") +OUTPUT_ARCH(sparc) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) } +} diff --git a/qemu/qemu-git/sparc64.ld b/qemu/qemu-git/sparc64.ld new file mode 100644 index 0000000..9ea4143 --- /dev/null +++ b/qemu/qemu-git/sparc64.ld @@ -0,0 +1,138 @@ +OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", + "elf64-sparc") +OUTPUT_ARCH(sparc:v9) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.gen_code) + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/qemu/qemu-git/target-arm/.svn/all-wcprops b/qemu/qemu-git/target-arm/.svn/all-wcprops new file mode 100644 index 0000000..f762d52 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/all-wcprops @@ -0,0 +1,59 @@ +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm +END +neon_helper.c +K 25 +svn:wc:ra_dav:version-url +V 64 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/neon_helper.c +END +helper.c +K 25 +svn:wc:ra_dav:version-url +V 59 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/helper.c +END +iwmmxt_helper.c +K 25 +svn:wc:ra_dav:version-url +V 66 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/iwmmxt_helper.c +END +op_addsub.h +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/op_addsub.h +END +helpers.h +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/helpers.h +END +exec.h +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/exec.h +END +cpu.h +K 25 +svn:wc:ra_dav:version-url +V 56 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/cpu.h +END +op_helper.c +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/op_helper.c +END +translate.c +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/target-arm/translate.c +END diff --git a/qemu/qemu-git/target-arm/.svn/entries b/qemu/qemu-git/target-arm/.svn/entries new file mode 100644 index 0000000..f1e4908 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/entries @@ -0,0 +1,334 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/target-arm +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +neon_helper.c +file + + + + +2013-08-23T00:54:48.000000Z +18af6516540342d43df7cc8892c5f4be +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +35208 + +helper.c +file + + + + +2013-08-23T00:54:48.000000Z +823155c4d333cf222454e866d2ce7d5f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +73283 + +iwmmxt_helper.c +file + + + + +2013-08-23T00:54:48.000000Z +8250353c2a25355004e2a16e16a7790f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +25270 + +op_addsub.h +file + + + + +2013-08-23T00:54:48.000000Z +b6b4efec5d913f6524d22b51e6c35b1e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1841 + +helpers.h +file + + + + +2013-08-23T00:54:48.000000Z +776a9380263a7c3b95531f8b96a2bcff +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +16327 + +exec.h +file + + + + +2013-08-23T00:54:48.000000Z +c2acd2fca23a0a1e0bbb05d36948c4ba +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +1603 + +cpu.h +file + + + + +2013-08-23T00:54:48.000000Z +354b69a5f0344806d9016a0e988a0a4d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +14765 + +op_helper.c +file + + + + +2013-08-23T00:54:48.000000Z +c0efc1eb0fd92046061b3ce8fc79437f +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +10951 + +translate.c +file + + + + +2013-08-23T00:54:48.000000Z +cb17dd22f174b2437221c58d73ab9e53 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +317978 + diff --git a/qemu/qemu-git/target-arm/.svn/text-base/cpu.h.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/cpu.h.svn-base new file mode 100644 index 0000000..a75a5be --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/cpu.h.svn-base @@ -0,0 +1,457 @@ +/* + * ARM virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_ARM_H +#define CPU_ARM_H + +#define TARGET_LONG_BITS 32 + +#define ELF_MACHINE EM_ARM + +#define CPUState struct CPUARMState + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define TARGET_HAS_ICE 1 + +#define EXCP_UDEF 1 /* undefined instruction */ +#define EXCP_SWI 2 /* software interrupt */ +#define EXCP_PREFETCH_ABORT 3 +#define EXCP_DATA_ABORT 4 +#define EXCP_IRQ 5 +#define EXCP_FIQ 6 +#define EXCP_BKPT 7 +#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ +#define EXCP_STREX 10 + +#define ARMV7M_EXCP_RESET 1 +#define ARMV7M_EXCP_NMI 2 +#define ARMV7M_EXCP_HARD 3 +#define ARMV7M_EXCP_MEM 4 +#define ARMV7M_EXCP_BUS 5 +#define ARMV7M_EXCP_USAGE 6 +#define ARMV7M_EXCP_SVC 11 +#define ARMV7M_EXCP_DEBUG 12 +#define ARMV7M_EXCP_PENDSV 14 +#define ARMV7M_EXCP_SYSTICK 15 + +typedef void ARMWriteCPFunc(void *opaque, int cp_info, + int srcreg, int operand, uint32_t value); +typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, + int dstreg, int operand); + +struct arm_boot_info; + +#define NB_MMU_MODES 2 + +/* We currently assume float and double are IEEE single and double + precision respectively. + Doing runtime conversions is tricky because VFP registers may contain + integer values (eg. as the result of a FTOSI instruction). + s<2n> maps to the least significant half of d + s<2n+1> maps to the most significant half of d + */ + +typedef struct CPUARMState { + /* Regs for current mode. */ + uint32_t regs[16]; + /* Frequently accessed CPSR bits are stored separately for efficiently. + This contains all the other bits. Use cpsr_{read,write} to access + the whole CPSR. */ + uint32_t uncached_cpsr; + uint32_t spsr; + + /* Banked registers. */ + uint32_t banked_spsr[6]; + uint32_t banked_r13[6]; + uint32_t banked_r14[6]; + + /* These hold r8-r12. */ + uint32_t usr_regs[5]; + uint32_t fiq_regs[5]; + + /* cpsr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NF; /* N is bit 31. All other bits are undefined. */ + uint32_t ZF; /* Z set if zero. */ + uint32_t QF; /* 0 or 1 */ + uint32_t GE; /* cpsr[19:16] */ + uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */ + uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */ + + /* System control coprocessor (cp15) */ + struct { + uint32_t c0_cpuid; + uint32_t c0_cachetype; + uint32_t c0_ccsid[16]; /* Cache size. */ + uint32_t c0_clid; /* Cache level. */ + uint32_t c0_cssel; /* Cache size selection. */ + uint32_t c0_c1[8]; /* Feature registers. */ + uint32_t c0_c2[8]; /* Instruction set registers. */ + uint32_t c1_sys; /* System control register. */ + uint32_t c1_coproc; /* Coprocessor access register. */ + uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ + uint32_t c2_base0; /* MMU translation table base 0. */ + uint32_t c2_base1; /* MMU translation table base 1. */ + uint32_t c2_control; /* MMU translation table base control. */ + uint32_t c2_mask; /* MMU translation table base selection mask. */ + uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ + uint32_t c2_data; /* MPU data cachable bits. */ + uint32_t c2_insn; /* MPU instruction cachable bits. */ + uint32_t c3; /* MMU domain access control register + MPU write buffer control. */ + uint32_t c5_insn; /* Fault status registers. */ + uint32_t c5_data; + uint32_t c6_region[8]; /* MPU base/size registers. */ + uint32_t c6_insn; /* Fault address registers. */ + uint32_t c6_data; + uint32_t c9_insn; /* Cache lockdown registers. */ + uint32_t c9_data; + uint32_t c13_fcse; /* FCSE PID. */ + uint32_t c13_context; /* Context ID. */ + uint32_t c13_tls1; /* User RW Thread register. */ + uint32_t c13_tls2; /* User RO Thread register. */ + uint32_t c13_tls3; /* Privileged Thread register. */ + uint32_t c15_cpar; /* XScale Coprocessor Access Register */ + uint32_t c15_ticonfig; /* TI925T configuration byte. */ + uint32_t c15_i_max; /* Maximum D-cache dirty line index. */ + uint32_t c15_i_min; /* Minimum D-cache dirty line index. */ + uint32_t c15_threadid; /* TI debugger thread-ID. */ + } cp15; + + struct { + uint32_t other_sp; + uint32_t vecbase; + uint32_t basepri; + uint32_t control; + int current_sp; + int exception; + int pending_exception; + void *nvic; + } v7m; + + /* Coprocessor IO used by peripherals */ + struct { + ARMReadCPFunc *cp_read; + ARMWriteCPFunc *cp_write; + void *opaque; + } cp[15]; + + /* Thumb-2 EE state. */ + uint32_t teecr; + uint32_t teehbr; + + /* Internal CPU feature flags. */ + uint32_t features; + + /* Callback for vectored interrupt controller. */ + int (*get_irq_vector)(struct CPUARMState *); + void *irq_opaque; + + /* VFP coprocessor state. */ + struct { + float64 regs[32]; + + uint32_t xregs[16]; + /* We store these fpcsr fields separately for convenience. */ + int vec_len; + int vec_stride; + + /* scratch space when Tn are not sufficient. */ + uint32_t scratch[8]; + + float_status fp_status; + } vfp; + uint32_t exclusive_addr; + uint32_t exclusive_val; + uint32_t exclusive_high; +#if defined(CONFIG_USER_ONLY) + uint32_t exclusive_test; + uint32_t exclusive_info; +#endif + + /* iwMMXt coprocessor state. */ + struct { + uint64_t regs[16]; + uint64_t val; + + uint32_t cregs[16]; + } iwmmxt; + +#if defined(CONFIG_USER_ONLY) + /* For usermode syscall translation. */ + int eabi; +#endif + + CPU_COMMON + + /* These fields after the common ones so they are preserved on reset. */ + struct arm_boot_info *boot_info; +} CPUARMState; + +CPUARMState *cpu_arm_init(const char *cpu_model); +void arm_translate_init(void); +int cpu_arm_exec(CPUARMState *s); +void cpu_arm_close(CPUARMState *s); +void do_interrupt(CPUARMState *); +void switch_mode(CPUARMState *, int); +uint32_t do_arm_semihosting(CPUARMState *env); + +/* 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. */ +int cpu_arm_signal_handler(int host_signum, void *pinfo, + void *puc); +int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw, + int mmu_idx, int is_softmuu); +#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault + +void cpu_lock(void); +void cpu_unlock(void); +static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) +{ + env->cp15.c13_tls2 = newtls; +} + +#define CPSR_M (0x1f) +#define CPSR_T (1 << 5) +#define CPSR_F (1 << 6) +#define CPSR_I (1 << 7) +#define CPSR_A (1 << 8) +#define CPSR_E (1 << 9) +#define CPSR_IT_2_7 (0xfc00) +#define CPSR_GE (0xf << 16) +#define CPSR_RESERVED (0xf << 20) +#define CPSR_J (1 << 24) +#define CPSR_IT_0_1 (3 << 25) +#define CPSR_Q (1 << 27) +#define CPSR_V (1 << 28) +#define CPSR_C (1 << 29) +#define CPSR_Z (1 << 30) +#define CPSR_N (1 << 31) +#define CPSR_NZCV (CPSR_N | CPSR_Z | CPSR_C | CPSR_V) + +#define CPSR_IT (CPSR_IT_0_1 | CPSR_IT_2_7) +#define CACHED_CPSR_BITS (CPSR_T | CPSR_GE | CPSR_IT | CPSR_Q | CPSR_NZCV) +/* Bits writable in user mode. */ +#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE) +/* Execution state bits. MRS read as zero, MSR writes ignored. */ +#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) + +/* Return the current CPSR value. */ +uint32_t cpsr_read(CPUARMState *env); +/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask); + +/* Return the current xPSR value. */ +static inline uint32_t xpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->ZF == 0); + return (env->NF & 0x80000000) | (ZF << 30) + | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | env->v7m.exception; +} + +/* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ +static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + if (mask & CPSR_NZCV) { + env->ZF = (~val) & CPSR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & (1 << 24)) + env->thumb = ((val & (1 << 24)) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & 0x1ff) { + env->v7m.exception = val & 0x1ff; + } +} + +enum arm_cpu_mode { + ARM_CPU_MODE_USR = 0x10, + ARM_CPU_MODE_FIQ = 0x11, + ARM_CPU_MODE_IRQ = 0x12, + ARM_CPU_MODE_SVC = 0x13, + ARM_CPU_MODE_ABT = 0x17, + ARM_CPU_MODE_UND = 0x1b, + ARM_CPU_MODE_SYS = 0x1f +}; + +/* VFP system registers. */ +#define ARM_VFP_FPSID 0 +#define ARM_VFP_FPSCR 1 +#define ARM_VFP_MVFR1 6 +#define ARM_VFP_MVFR0 7 +#define ARM_VFP_FPEXC 8 +#define ARM_VFP_FPINST 9 +#define ARM_VFP_FPINST2 10 + +/* iwMMXt coprocessor control registers. */ +#define ARM_IWMMXT_wCID 0 +#define ARM_IWMMXT_wCon 1 +#define ARM_IWMMXT_wCSSF 2 +#define ARM_IWMMXT_wCASF 3 +#define ARM_IWMMXT_wCGR0 8 +#define ARM_IWMMXT_wCGR1 9 +#define ARM_IWMMXT_wCGR2 10 +#define ARM_IWMMXT_wCGR3 11 + +enum arm_features { + ARM_FEATURE_VFP, + ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ + ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ + ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ + ARM_FEATURE_V6, + ARM_FEATURE_V6K, + ARM_FEATURE_V7, + ARM_FEATURE_THUMB2, + ARM_FEATURE_MPU, /* Only has Memory Protection Unit, not full MMU. */ + ARM_FEATURE_VFP3, + ARM_FEATURE_VFP_FP16, + ARM_FEATURE_NEON, + ARM_FEATURE_DIV, + ARM_FEATURE_M, /* Microcontroller profile. */ + ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ + ARM_FEATURE_THUMB2EE +}; + +static inline int arm_feature(CPUARMState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +/* Interface between CPU and Interrupt controller. */ +void armv7m_nvic_set_pending(void *opaque, int irq); +int armv7m_nvic_acknowledge_irq(void *opaque); +void armv7m_nvic_complete_irq(void *opaque, int irq); + +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque); + +/* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3. + Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are + conventional cores (ie. Application or Realtime profile). */ + +#define IS_M(env) arm_feature(env, ARM_FEATURE_M) +#define ARM_CPUID(env) (env->cp15.c0_cpuid) + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_ARM946 0x41059461 +#define ARM_CPUID_TI915T 0x54029152 +#define ARM_CPUID_TI925T 0x54029252 +#define ARM_CPUID_PXA250 0x69052100 +#define ARM_CPUID_PXA255 0x69052d00 +#define ARM_CPUID_PXA260 0x69052903 +#define ARM_CPUID_PXA261 0x69052d05 +#define ARM_CPUID_PXA262 0x69052d06 +#define ARM_CPUID_PXA270 0x69054110 +#define ARM_CPUID_PXA270_A0 0x69054110 +#define ARM_CPUID_PXA270_A1 0x69054111 +#define ARM_CPUID_PXA270_B0 0x69054112 +#define ARM_CPUID_PXA270_B1 0x69054113 +#define ARM_CPUID_PXA270_C0 0x69054114 +#define ARM_CPUID_PXA270_C5 0x69054117 +#define ARM_CPUID_ARM1136 0x4117b363 +#define ARM_CPUID_ARM1136_R2 0x4107b362 +#define ARM_CPUID_ARM11MPCORE 0x410fb022 +#define ARM_CPUID_CORTEXA8 0x410fc080 +#define ARM_CPUID_CORTEXA9 0x410fc090 +#define ARM_CPUID_CORTEXM3 0x410fc231 +#define ARM_CPUID_ANY 0xffffffff + +#if defined(CONFIG_USER_ONLY) +#define TARGET_PAGE_BITS 12 +#else +/* The ARM MMU allows 1k pages. */ +/* ??? Linux doesn't actually use these, and they're deprecated in recent + architecture revisions. Maybe a configure option to disable them. */ +#define TARGET_PAGE_BITS 10 +#endif + +#define cpu_init cpu_arm_init +#define cpu_exec cpu_arm_exec +#define cpu_gen_code cpu_arm_gen_code +#define cpu_signal_handler cpu_arm_signal_handler +#define cpu_list arm_cpu_list + +#ifndef X49GP +#define CPU_SAVE_VERSION 2 +#endif + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0; +} + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[13] = newsp; + env->regs[0] = 0; +} +#endif + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->regs[15] = tb->pc; +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->regs[15]; + *cs_base = 0; + *flags = env->thumb | (env->vfp.vec_len << 1) + | (env->vfp.vec_stride << 4) | (env->condexec_bits << 8); + if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) + *flags |= (1 << 6); + if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) + *flags |= (1 << 7); +} + +#endif diff --git a/qemu/qemu-git/target-arm/.svn/text-base/exec.h.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/exec.h.svn-base new file mode 100644 index 0000000..e9848e1 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/exec.h.svn-base @@ -0,0 +1,60 @@ +/* + * ARM execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#include "dyngen-exec.h" + +register struct CPUARMState *env asm(AREG0); + +#define M0 env->iwmmxt.val + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +static inline int cpu_has_work(CPUState *env) +{ + return (env->interrupt_request & + (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)); +} + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + /* An interrupt wakes the CPU even if the I and F CPSR bits are + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (cpu_has_work(env)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +void raise_exception(int); diff --git a/qemu/qemu-git/target-arm/.svn/text-base/helper.c.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/helper.c.svn-base new file mode 100644 index 0000000..b3aec99 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/helper.c.svn-base @@ -0,0 +1,2598 @@ +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "helpers.h" +#include "qemu-common.h" +#include "host-utils.h" + +static uint32_t cortexa9_cp15_c0_c1[8] = +{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 }; + +static uint32_t cortexa9_cp15_c0_c2[8] = +{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 }; + +static uint32_t cortexa8_cp15_c0_c1[8] = +{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 }; + +static uint32_t cortexa8_cp15_c0_c2[8] = +{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 }; + +static uint32_t mpcore_cp15_c0_c1[8] = +{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 }; + +static uint32_t mpcore_cp15_c0_c2[8] = +{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 }; + +static uint32_t arm1136_cp15_c0_c1[8] = +{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 }; + +static uint32_t arm1136_cp15_c0_c2[8] = +{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 }; + +static uint32_t cpu_arm_find_by_name(const char *name); + +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1u << feature; +} + +static void cpu_reset_model_id(CPUARMState *env, uint32_t id) +{ + env->cp15.c0_cpuid = id; + switch (id) { + case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_VFP); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; + break; + case ARM_CPUID_ARM946: + set_feature(env, ARM_FEATURE_MPU); + env->cp15.c0_cachetype = 0x0f004006; + env->cp15.c1_sys = 0x00000078; + break; + case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; + break; + case ARM_CPUID_ARM1136_R2: + case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_ARM11MPCORE: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_CORTEXA8: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; + memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x82048004; + env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3; + env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */ + env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */ + env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */ + break; + case ARM_CPUID_CORTEXA9: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_VFP_FP16); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */ + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111; + memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x80038003; + env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3; + env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */ + env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */ + break; + case ARM_CPUID_CORTEXM3: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_M); + set_feature(env, ARM_FEATURE_DIV); + break; + case ARM_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_VFP_FP16); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + set_feature(env, ARM_FEATURE_DIV); + break; + case ARM_CPUID_TI915T: + case ARM_CPUID_TI925T: + set_feature(env, ARM_FEATURE_OMAPCP); + env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */ + env->cp15.c0_cachetype = 0x5109149; + env->cp15.c1_sys = 0x00000070; + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + break; + case ARM_CPUID_PXA250: + case ARM_CPUID_PXA255: + case ARM_CPUID_PXA260: + case ARM_CPUID_PXA261: + case ARM_CPUID_PXA262: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; + break; + case ARM_CPUID_PXA270_A0: + case ARM_CPUID_PXA270_A1: + case ARM_CPUID_PXA270_B0: + case ARM_CPUID_PXA270_B1: + case ARM_CPUID_PXA270_C0: + case ARM_CPUID_PXA270_C5: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + set_feature(env, ARM_FEATURE_IWMMXT); + env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; + env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + break; + } +} + +void cpu_reset(CPUARMState *env) +{ + uint32_t id; + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + + id = env->cp15.c0_cpuid; + memset(env, 0, offsetof(CPUARMState, breakpoints)); + if (id) + cpu_reset_model_id(env, id); +#if defined (CONFIG_USER_ONLY) + env->uncached_cpsr = ARM_CPU_MODE_USR; + env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30; +#else + /* SVC mode with interrupts disabled. */ + env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is + clear at reset. */ + if (IS_M(env)) + env->uncached_cpsr &= ~CPSR_I; + env->vfp.xregs[ARM_VFP_FPEXC] = 0; + env->cp15.c2_base_mask = 0xffffc000u; +#endif + env->regs[15] = 0; + tlb_flush(env, 1); +} + +static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + /* VFP data registers are always little-endian. */ + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[reg]); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + /* Aliases for Q regs. */ + nregs += 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]); + stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]); + return 16; + } + } + switch (reg - nregs) { + case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4; + case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4; + case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4; + } + return 0; +} + +static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + env->vfp.regs[reg] = ldfq_le_p(buf); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + nregs += 16; + if (reg < nregs) { + env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf); + env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8); + return 16; + } + } + switch (reg - nregs) { + case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4; + case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4; + case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); return 4; + } + return 0; +} + +CPUARMState *cpu_arm_init(const char *cpu_model) +{ + CPUARMState *env; + uint32_t id; + static int inited = 0; + + id = cpu_arm_find_by_name(cpu_model); + if (id == 0) + return NULL; + env = qemu_mallocz(sizeof(CPUARMState)); + cpu_exec_init(env); + if (!inited) { + inited = 1; + arm_translate_init(); + } + + env->cpu_model_str = cpu_model; + env->cp15.c0_cpuid = id; + cpu_reset(env); + if (arm_feature(env, ARM_FEATURE_NEON)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 51, "arm-neon.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP3)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 35, "arm-vfp3.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 19, "arm-vfp.xml", 0); + } + qemu_init_vcpu(env); + return env; +} + +struct arm_cpu_t { + uint32_t id; + const char *name; +}; + +static const struct arm_cpu_t arm_cpu_names[] = { + { ARM_CPUID_ARM926, "arm926"}, + { ARM_CPUID_ARM946, "arm946"}, + { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_ARM1136, "arm1136"}, + { ARM_CPUID_ARM1136_R2, "arm1136-r2"}, + { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, + { ARM_CPUID_CORTEXM3, "cortex-m3"}, + { ARM_CPUID_CORTEXA8, "cortex-a8"}, + { ARM_CPUID_CORTEXA9, "cortex-a9"}, + { ARM_CPUID_TI925T, "ti925t" }, + { ARM_CPUID_PXA250, "pxa250" }, + { ARM_CPUID_PXA255, "pxa255" }, + { ARM_CPUID_PXA260, "pxa260" }, + { ARM_CPUID_PXA261, "pxa261" }, + { ARM_CPUID_PXA262, "pxa262" }, + { ARM_CPUID_PXA270, "pxa270" }, + { ARM_CPUID_PXA270_A0, "pxa270-a0" }, + { ARM_CPUID_PXA270_A1, "pxa270-a1" }, + { ARM_CPUID_PXA270_B0, "pxa270-b0" }, + { ARM_CPUID_PXA270_B1, "pxa270-b1" }, + { ARM_CPUID_PXA270_C0, "pxa270-c0" }, + { ARM_CPUID_PXA270_C5, "pxa270-c5" }, + { ARM_CPUID_ANY, "any"}, + { 0, NULL} +}; + +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i; + + (*cpu_fprintf)(f, "Available CPUs:\n"); + for (i = 0; arm_cpu_names[i].name; i++) { + (*cpu_fprintf)(f, " %s\n", arm_cpu_names[i].name); + } +} + +/* return 0 if not found */ +static uint32_t cpu_arm_find_by_name(const char *name) +{ + int i; + uint32_t id; + + id = 0; + for (i = 0; arm_cpu_names[i].name; i++) { + if (strcmp(name, arm_cpu_names[i].name) == 0) { + id = arm_cpu_names[i].id; + break; + } + } + return id; +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + +uint32_t cpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->ZF == 0); + return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16); +} + +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + if (mask & CPSR_NZCV) { + env->ZF = (~val) & CPSR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & CPSR_T) + env->thumb = ((val & CPSR_T) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & CPSR_GE) { + env->GE = (val >> 16) & 0xf; + } + + if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { + switch_mode(env, val & CPSR_M); + } + mask &= ~CACHED_CPSR_BITS; + env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); +} + +/* Sign/zero extend */ +uint32_t HELPER(sxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(int8_t)x; + res |= (uint32_t)(int8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(uxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(uint8_t)x; + res |= (uint32_t)(uint8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(clz)(uint32_t x) +{ + return clz32(x); +} + +int32_t HELPER(sdiv)(int32_t num, int32_t den) +{ + if (den == 0) + return 0; + if (num == INT_MIN && den == -1) + return INT_MIN; + return num / den; +} + +uint32_t HELPER(udiv)(uint32_t num, uint32_t den) +{ + if (den == 0) + return 0; + return num / den; +} + +uint32_t HELPER(rbit)(uint32_t x) +{ + x = ((x & 0xff000000) >> 24) + | ((x & 0x00ff0000) >> 8) + | ((x & 0x0000ff00) << 8) + | ((x & 0x000000ff) << 24); + x = ((x & 0xf0f0f0f0) >> 4) + | ((x & 0x0f0f0f0f) << 4); + x = ((x & 0x88888888) >> 3) + | ((x & 0x44444444) >> 1) + | ((x & 0x22222222) << 1) + | ((x & 0x11111111) << 3); + return x; +} + +uint32_t HELPER(abs)(uint32_t x) +{ + return ((int32_t)x < 0) ? -x : x; +} + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + if (rw == 2) { + env->exception_index = EXCP_PREFETCH_ABORT; + env->cp15.c6_insn = address; + } else { + env->exception_index = EXCP_DATA_ABORT; + env->cp15.c6_data = address; + } + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return; +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return 0; +} + +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); +} + +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); + return 0; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); +} + +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); + return 0; +} + +void switch_mode(CPUState *env, int mode) +{ + if (mode != ARM_CPU_MODE_USR) + cpu_abort(env, "Tried to switch out of user mode\n"); +} + +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + cpu_abort(env, "banked r13 write\n"); +} + +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) +{ + cpu_abort(env, "banked r13 read\n"); + return 0; +} + +#else + +extern int semihosting_enabled; + +/* Map CPU modes onto saved register banks. */ +static inline int bank_number (int mode) +{ + switch (mode) { + case ARM_CPU_MODE_USR: + case ARM_CPU_MODE_SYS: + return 0; + case ARM_CPU_MODE_SVC: + return 1; + case ARM_CPU_MODE_ABT: + return 2; + case ARM_CPU_MODE_UND: + return 3; + case ARM_CPU_MODE_IRQ: + return 4; + case ARM_CPU_MODE_FIQ: + return 5; + } + cpu_abort(cpu_single_env, "Bad mode %x\n", mode); + return -1; +} + +void switch_mode(CPUState *env, int mode) +{ + int old_mode; + int i; + + old_mode = env->uncached_cpsr & CPSR_M; + if (mode == old_mode) + return; + + if (old_mode == ARM_CPU_MODE_FIQ) { + memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + } else if (mode == ARM_CPU_MODE_FIQ) { + memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + } + + i = bank_number(old_mode); + env->banked_r13[i] = env->regs[13]; + env->banked_r14[i] = env->regs[14]; + env->banked_spsr[i] = env->spsr; + + i = bank_number(mode); + env->regs[13] = env->banked_r13[i]; + env->regs[14] = env->banked_r14[i]; + env->spsr = env->banked_spsr[i]; +} + +static void v7m_push(CPUARMState *env, uint32_t val) +{ + env->regs[13] -= 4; + stl_phys(env->regs[13], val); +} + +static uint32_t v7m_pop(CPUARMState *env) +{ + uint32_t val; + val = ldl_phys(env->regs[13]); + env->regs[13] += 4; + return val; +} + +/* Switch to V7M main or process stack pointer. */ +static void switch_v7m_sp(CPUARMState *env, int process) +{ + uint32_t tmp; + if (env->v7m.current_sp != process) { + tmp = env->v7m.other_sp; + env->v7m.other_sp = env->regs[13]; + env->regs[13] = tmp; + env->v7m.current_sp = process; + } +} + +static void do_v7m_exception_exit(CPUARMState *env) +{ + uint32_t type; + uint32_t xpsr; + + type = env->regs[15]; + if (env->v7m.exception != 0) + armv7m_nvic_complete_irq(env->v7m.nvic, env->v7m.exception); + + /* Switch to the target stack. */ + switch_v7m_sp(env, (type & 4) != 0); + /* Pop registers. */ + env->regs[0] = v7m_pop(env); + env->regs[1] = v7m_pop(env); + env->regs[2] = v7m_pop(env); + env->regs[3] = v7m_pop(env); + env->regs[12] = v7m_pop(env); + env->regs[14] = v7m_pop(env); + env->regs[15] = v7m_pop(env); + xpsr = v7m_pop(env); + xpsr_write(env, xpsr, 0xfffffdff); + /* Undo stack alignment. */ + if (xpsr & 0x200) + env->regs[13] |= 4; + /* ??? The exception return type specifies Thread/Handler mode. However + this is also implied by the xPSR value. Not sure what to do + if there is a mismatch. */ + /* ??? Likewise for mismatches between the CONTROL register and the stack + pointer. */ +} + +static void do_interrupt_v7m(CPUARMState *env) +{ + uint32_t xpsr = xpsr_read(env); + uint32_t lr; + uint32_t addr; + + lr = 0xfffffff1; + if (env->v7m.current_sp) + lr |= 4; + if (env->v7m.exception == 0) + lr |= 8; + + /* For exceptions we just mark as pending on the NVIC, and let that + handle it. */ + /* TODO: Need to escalate if the current priority is higher than the + one we're raising. */ + switch (env->exception_index) { + case EXCP_UDEF: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE); + return; + case EXCP_SWI: + env->regs[15] += 2; + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC); + return; + case EXCP_PREFETCH_ABORT: + case EXCP_DATA_ABORT: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM); + return; + case EXCP_BKPT: + if (semihosting_enabled) { + int nr; + nr = lduw_code(env->regs[15]) & 0xff; + if (nr == 0xab) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); + return; + case EXCP_IRQ: + env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic); + break; + case EXCP_EXCEPTION_EXIT: + do_v7m_exception_exit(env); + return; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + + /* Align stack pointer. */ + /* ??? Should only do this if Configuration Control Register + STACKALIGN bit is set. */ + if (env->regs[13] & 4) { + env->regs[13] -= 4; + xpsr |= 0x200; + } + /* Switch to the handler mode. */ + v7m_push(env, xpsr); + v7m_push(env, env->regs[15]); + v7m_push(env, env->regs[14]); + v7m_push(env, env->regs[12]); + v7m_push(env, env->regs[3]); + v7m_push(env, env->regs[2]); + v7m_push(env, env->regs[1]); + v7m_push(env, env->regs[0]); + switch_v7m_sp(env, 0); + env->uncached_cpsr &= ~CPSR_IT; + env->regs[14] = lr; + addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4); + env->regs[15] = addr & 0xfffffffe; + env->thumb = addr & 1; +} + +/* Handle a CPU exception. */ +void do_interrupt(CPUARMState *env) +{ + uint32_t addr; + uint32_t mask; + int new_mode; + uint32_t offset; + + if (IS_M(env)) { + do_interrupt_v7m(env); + return; + } + /* TODO: Vectored interrupt controller. */ + switch (env->exception_index) { + case EXCP_UDEF: + new_mode = ARM_CPU_MODE_UND; + addr = 0x04; + mask = CPSR_I; + if (env->thumb) + offset = 2; + else + offset = 4; + break; + case EXCP_SWI: + if (semihosting_enabled) { + /* Check for semihosting interrupt. */ + if (env->thumb) { + mask = lduw_code(env->regs[15] - 2) & 0xff; + } else { + mask = ldl_code(env->regs[15] - 4) & 0xffffff; + } + /* Only intercept calls from privileged modes, to provide some + semblance of security. */ + if (((mask == 0x123456 && !env->thumb) + || (mask == 0xab && env->thumb)) + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[0] = do_arm_semihosting(env); + return; + } + } + new_mode = ARM_CPU_MODE_SVC; + addr = 0x08; + mask = CPSR_I; + /* The PC already points to the next instruction. */ + offset = 0; + break; + case EXCP_BKPT: + /* See if this is a semihosting syscall. */ + if (env->thumb && semihosting_enabled) { + mask = lduw_code(env->regs[15]) & 0xff; + if (mask == 0xab + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } + /* Fall through to prefetch abort. */ + case EXCP_PREFETCH_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x0c; + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_DATA_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + break; + case EXCP_IRQ: + new_mode = ARM_CPU_MODE_IRQ; + addr = 0x18; + /* Disable IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_FIQ: + new_mode = ARM_CPU_MODE_FIQ; + addr = 0x1c; + /* Disable FIQ, IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I | CPSR_F; + offset = 4; + break; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + /* High vectors. */ + if (env->cp15.c1_sys & (1 << 13)) { + addr += 0xffff0000; + } + switch_mode (env, new_mode); + env->spsr = cpsr_read(env); + /* Clear IT bits. */ + env->condexec_bits = 0; + /* Switch to the new mode, and switch to Arm mode. */ + /* ??? Thumb interrupt handlers not implemented. */ + env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; + env->uncached_cpsr |= mask; + env->thumb = 0; + env->regs[14] = env->regs[15] + offset; + env->regs[15] = addr; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +/* Check section/page access permissions. + Returns the page protection flags, or zero if the access is not + permitted. */ +static inline int check_ap(CPUState *env, int ap, int domain, int access_type, + int is_user) +{ + int prot_ro; + + if (domain == 3) + return PAGE_READ | PAGE_WRITE; + + if (access_type == 1) + prot_ro = 0; + else + prot_ro = PAGE_READ; + + switch (ap) { + case 0: + if (access_type == 1) + return 0; + switch ((env->cp15.c1_sys >> 8) & 3) { + case 1: + return is_user ? 0 : PAGE_READ; + case 2: + return PAGE_READ; + default: + return 0; + } + case 1: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 2: + if (is_user) + return prot_ro; + else + return PAGE_READ | PAGE_WRITE; + case 3: + return PAGE_READ | PAGE_WRITE; + case 4: /* Reserved. */ + return 0; + case 5: + return is_user ? 0 : prot_ro; + case 6: + return prot_ro; + case 7: + if (!arm_feature (env, ARM_FEATURE_V7)) + return 0; + return prot_ro; + default: + abort(); + } +} + +static uint32_t get_level1_table_address(CPUState *env, uint32_t address) +{ + uint32_t table; + + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1 & 0xffffc000; + else + table = env->cp15.c2_base0 & env->cp15.c2_base_mask; + + table |= (address >> 18) & 0x3ffc; + return table; +} + +static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + table = get_level1_table_address(env, address); + desc = ldl_phys(table); + type = (desc & 3); + domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; + if (type == 0) { + /* Section translation fault. */ + code = 5; + goto do_fault; + } + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + code = 13; + } else { + /* Lookup l2 entry. */ + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } + desc = ldl_phys(table); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 3: /* 1k page. */ + if (type == 1) { + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + } else { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + } + ap = (desc >> 4) & 3; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); + } + code = 15; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + return 0; +do_fault: + return code | (domain << 4); +} + +static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + uint32_t xn; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + table = get_level1_table_address(env, address); + desc = ldl_phys(table); + type = (desc & 3); + if (type == 0) { + /* Section translation fault. */ + code = 5; + domain = 0; + goto do_fault; + } else if (type == 2 && (desc & (1 << 18))) { + /* Supersection. */ + domain = 0; + } else { + /* Section or page. */ + domain = (desc >> 4) & 0x1e; + } + domain = (env->cp15.c3 >> domain) & 3; + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + if (desc & (1 << 18)) { + /* Supersection. */ + phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); + } else { + /* Section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + } + ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); + xn = desc & (1 << 4); + code = 13; + } else { + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + desc = ldl_phys(table); + ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + xn = desc & (1 << 15); + break; + case 2: case 3: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + xn = desc & 1; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); + } + code = 15; + } + if (xn && access_type == 2) + goto do_fault; + + /* The simplified model uses AP[0] as an access control bit. */ + if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) { + /* Access flag fault. */ + code = (code == 15) ? 6 : 3; + goto do_fault; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + return 0; +do_fault: + return code | (domain << 4); +} + +static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int n; + uint32_t mask; + uint32_t base; + + *phys_ptr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) + continue; + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) + break; + } + if (n < 0) + return 2; + + if (access_type == 2) { + mask = env->cp15.c5_insn; + } else { + mask = env->cp15.c5_data; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + return 1; + case 1: + if (is_user) + return 1; + *prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + *prot = PAGE_READ; + if (!is_user) + *prot |= PAGE_WRITE; + break; + case 3: + *prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) + return 1; + *prot = PAGE_READ; + break; + case 6: + *prot = PAGE_READ; + break; + default: + /* Bad permission. */ + return 1; + } + return 0; +} + +static inline int get_phys_addr(CPUState *env, uint32_t address, + int access_type, int is_user, + uint32_t *phys_ptr, int *prot) +{ + /* Fast Context Switch Extension. */ + if (address < 0x02000000) + address += env->cp15.c13_fcse; + + if ((env->cp15.c1_sys & 1) == 0) { + /* MMU/MPU disabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } else if (arm_feature(env, ARM_FEATURE_MPU)) { + return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, + prot); + } else if (env->cp15.c1_sys & (1 << 23)) { + return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, + prot); + } else { + return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr, + prot); + } +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, + int access_type, int mmu_idx, int is_softmmu) +{ + uint32_t phys_addr; + int prot; + int ret, is_user; + + is_user = mmu_idx == MMU_USER_IDX; + ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); + if (ret == 0) { + /* Map a single [sub]page. */ + phys_addr &= ~(uint32_t)0x3ff; + address &= ~(uint32_t)0x3ff; + return tlb_set_page (env, address, phys_addr, prot, mmu_idx, + is_softmmu); + } + + if (access_type == 2) { + env->cp15.c5_insn = ret; + env->cp15.c6_insn = address; + env->exception_index = EXCP_PREFETCH_ABORT; + } else { + env->cp15.c5_data = ret; + if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) + env->cp15.c5_data |= (1 << 11); + env->cp15.c6_data = address; + env->exception_index = EXCP_DATA_ABORT; + } + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot; + int ret; + + ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot); + + if (ret != 0) + return -1; + + return phys_addr; +} + +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int src = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_write) + env->cp[cp_num].cp_write(env->cp[cp_num].opaque, + cp_info, src, operand, val); +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int dest = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_read) + return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, + cp_info, dest, operand); + return 0; +} + +/* Return basic MPU access permission bits. */ +static uint32_t simple_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val >> i) & mask; + mask <<= 2; + } + return ret; +} + +/* Pad basic MPU access permission bits to extended format. */ +static uint32_t extended_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val & mask) << i; + mask <<= 2; + } + return ret; +} + +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1; + int op2; + int crm; + + op1 = (insn >> 21) & 7; + op2 = (insn >> 5) & 7; + crm = insn & 0xf; + switch ((insn >> 16) & 0xf) { + case 0: + /* ID codes. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + break; + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; + if (arm_feature(env, ARM_FEATURE_V7) + && op1 == 2 && crm == 0 && op2 == 0) { + env->cp15.c0_cssel = val & 0xf; + break; + } + goto bad_reg; + case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) + env->cp15.c1_sys = val; + /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ + tlb_flush(env, 1); + break; + case 1: /* Auxiliary cotrol register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + env->cp15.c1_xscaleauxcr = val; + break; + } + /* Not implemented. */ + break; + case 2: + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; + if (env->cp15.c1_coproc != val) { + env->cp15.c1_coproc = val; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + } + break; + default: + goto bad_reg; + } + break; + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + env->cp15.c2_data = val; + break; + case 1: + env->cp15.c2_insn = val; + break; + default: + goto bad_reg; + } + } else { + switch (op2) { + case 0: + env->cp15.c2_base0 = val; + break; + case 1: + env->cp15.c2_base1 = val; + break; + case 2: + val &= 7; + env->cp15.c2_control = val; + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); + break; + default: + goto bad_reg; + } + } + break; + case 3: /* MMU Domain access control / MPU write buffer control. */ + env->cp15.c3 = val; + tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ + break; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); + env->cp15.c5_data = val; + break; + case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); + env->cp15.c5_insn = val; + break; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_data = val; + break; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_insn = val; + break; + default: + goto bad_reg; + } + break; + case 6: /* MMU Fault address / MPU base/size. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + if (crm >= 8) + goto bad_reg; + env->cp15.c6_region[crm] = val; + } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + env->cp15.c6_data = val; + break; + case 1: /* ??? This is WFAR on armv6 */ + case 2: + env->cp15.c6_insn = val; + break; + default: + goto bad_reg; + } + } + break; + case 7: /* Cache control. */ + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + /* No cache, so nothing to do. */ + /* ??? MPCore has VA to PA translation functions. */ + break; + case 8: /* MMU TLB control. */ + switch (op2) { + case 0: /* Invalidate all. */ + tlb_flush(env, 0); + break; + case 1: /* Invalidate single TLB entry. */ +#if 0 + /* ??? This is wrong for large pages and sections. */ + /* As an ugly hack to make linux work we always flush a 4K + pages. */ + val &= 0xfffff000; + tlb_flush_page(env, val); + tlb_flush_page(env, val + 0x400); + tlb_flush_page(env, val + 0x800); + tlb_flush_page(env, val + 0xc00); +#else + tlb_flush(env, 1); +#endif + break; + case 2: /* Invalidate on ASID. */ + tlb_flush(env, val == 0); + break; + case 3: /* Invalidate single entry on MVA. */ + /* ??? This is like case 1, but ignores ASID. */ + tlb_flush(env, 1); + break; + default: + goto bad_reg; + } + break; + case 9: + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; + switch (crm) { + case 0: /* Cache lockdown. */ + switch (op1) { + case 0: /* L1 cache. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 1: /* L2 cache. */ + /* Ignore writes to L2 lockdown/auxiliary registers. */ + break; + default: + goto bad_reg; + } + break; + case 1: /* TCM memory region registers. */ + /* Not implemented. */ + goto bad_reg; + default: + goto bad_reg; + } + break; + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + break; + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + /* Unlike real hardware the qemu TLB uses virtual addresses, + not modified virtual addresses, so this causes a TLB flush. + */ + if (env->cp15.c13_fcse != val) + tlb_flush(env, 1); + env->cp15.c13_fcse = val; + break; + case 1: + /* This changes the ASID, so do a TLB flush. */ + if (env->cp15.c13_context != val + && !arm_feature(env, ARM_FEATURE_MPU)) + tlb_flush(env, 0); + env->cp15.c13_context = val; + break; + case 2: + env->cp15.c13_tls1 = val; + break; + case 3: + env->cp15.c13_tls2 = val; + break; + case 4: + env->cp15.c13_tls3 = val; + break; + default: + goto bad_reg; + } + break; + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && crm == 1) { + if (env->cp15.c15_cpar != (val & 0x3fff)) { + /* Changes cp0 to cp13 behavior, so needs a TB flush. */ + tb_flush(env); + env->cp15.c15_cpar = val & 0x3fff; + } + break; + } + goto bad_reg; + } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + break; + case 1: /* Set TI925T configuration. */ + env->cp15.c15_ticonfig = val & 0xe7; + env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */ + ARM_CPUID_TI915T : ARM_CPUID_TI925T; + break; + case 2: /* Set I_max. */ + env->cp15.c15_i_max = val; + break; + case 3: /* Set I_min. */ + env->cp15.c15_i_min = val; + break; + case 4: /* Set thread-ID. */ + env->cp15.c15_threadid = val & 0xffff; + break; + case 8: /* Wait-for-interrupt (deprecated). */ + cpu_interrupt(env, CPU_INTERRUPT_HALT); + break; + default: + goto bad_reg; + } + } + break; + } + return; +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); +} + +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) +{ + int op1; + int op2; + int crm; + + op1 = (insn >> 21) & 7; + op2 = (insn >> 5) & 7; + crm = insn & 0xf; + switch ((insn >> 16) & 0xf) { + case 0: /* ID codes. */ + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: /* Device ID. */ + return env->cp15.c0_cpuid; + case 1: /* Cache Type. */ + return env->cp15.c0_cachetype; + case 2: /* TCM status. */ + return 0; + case 3: /* TLB type register. */ + return 0; /* No lockable TLB entries. */ + case 5: /* CPU ID */ + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) { + return env->cpu_index | 0x80000900; + } else { + return env->cpu_index; + } + default: + goto bad_reg; + } + case 1: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c1[op2]; + case 2: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c2[op2]; + case 3: case 4: case 5: case 6: case 7: + return 0; + default: + goto bad_reg; + } + case 1: + /* These registers aren't documented on arm11 cores. However + Linux looks at them anyway. */ + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + if (crm != 0) + goto bad_reg; + if (!arm_feature(env, ARM_FEATURE_V7)) + return 0; + + switch (op2) { + case 0: + return env->cp15.c0_ccsid[env->cp15.c0_cssel]; + case 1: + return env->cp15.c0_clid; + case 7: + return 0; + } + goto bad_reg; + case 2: + if (op2 != 0 || crm != 0) + goto bad_reg; + return env->cp15.c0_cssel; + default: + goto bad_reg; + } + case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: /* Control register. */ + return env->cp15.c1_sys; + case 1: /* Auxiliary control register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + return env->cp15.c1_xscaleauxcr; + if (!arm_feature(env, ARM_FEATURE_AUXCR)) + goto bad_reg; + switch (ARM_CPUID(env)) { + case ARM_CPUID_ARM1026: + return 1; + case ARM_CPUID_ARM1136: + case ARM_CPUID_ARM1136_R2: + return 7; + case ARM_CPUID_ARM11MPCORE: + return 1; + case ARM_CPUID_CORTEXA8: + return 2; + case ARM_CPUID_CORTEXA9: + return 0; + default: + goto bad_reg; + } + case 2: /* Coprocessor access register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; + return env->cp15.c1_coproc; + default: + goto bad_reg; + } + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + return env->cp15.c2_data; + break; + case 1: + return env->cp15.c2_insn; + break; + default: + goto bad_reg; + } + } else { + switch (op2) { + case 0: + return env->cp15.c2_base0; + case 1: + return env->cp15.c2_base1; + case 2: + return env->cp15.c2_control; + default: + goto bad_reg; + } + } + case 3: /* MMU Domain access control / MPU write buffer control. */ + return env->cp15.c3; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); + return env->cp15.c5_data; + case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); + return env->cp15.c5_insn; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + return env->cp15.c5_data; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + return env->cp15.c5_insn; + default: + goto bad_reg; + } + case 6: /* MMU Fault address. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + if (crm >= 8) + goto bad_reg; + return env->cp15.c6_region[crm]; + } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Watchpoint Fault Adrress. */ + return 0; /* Not implemented. */ + } else { + /* Instruction Fault Adrress. */ + /* Arm9 doesn't have an IFAR, but implementing it anyway + shouldn't do any harm. */ + return env->cp15.c6_insn; + } + case 2: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Instruction Fault Adrress. */ + return env->cp15.c6_insn; + } else { + goto bad_reg; + } + default: + goto bad_reg; + } + } + case 7: /* Cache control. */ + /* FIXME: Should only clear Z flag if destination is r15. */ + env->ZF = 0; + return 0; + case 8: /* MMU TLB control. */ + goto bad_reg; + case 9: /* Cache lockdown. */ + switch (op1) { + case 0: /* L1 cache. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + return 0; + switch (op2) { + case 0: + return env->cp15.c9_data; + case 1: + return env->cp15.c9_insn; + default: + goto bad_reg; + } + case 1: /* L2 cache */ + if (crm != 0) + goto bad_reg; + /* L2 Lockdown and Auxiliary control. */ + return 0; + default: + goto bad_reg; + } + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + return 0; + case 11: /* TCM DMA control. */ + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + return env->cp15.c13_fcse; + case 1: + return env->cp15.c13_context; + case 2: + return env->cp15.c13_tls1; + case 3: + return env->cp15.c13_tls2; + case 4: + return env->cp15.c13_tls3; + default: + goto bad_reg; + } + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && crm == 1) + return env->cp15.c15_cpar; + + goto bad_reg; + } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + return 0; + case 1: /* Read TI925T configuration. */ + return env->cp15.c15_ticonfig; + case 2: /* Read I_max. */ + return env->cp15.c15_i_max; + case 3: /* Read I_min. */ + return env->cp15.c15_i_min; + case 4: /* Read thread-ID. */ + return env->cp15.c15_threadid; + case 8: /* TI925T_status */ + return 0; + } + /* TODO: Peripheral port remap register: + * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt + * controller base address at $rn & ~0xfff and map size of + * 0x200 << ($rn & 0xfff), when MMU is off. */ + goto bad_reg; + } + return 0; + } +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); + return 0; +} + +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + env->banked_r13[bank_number(mode)] = val; +} + +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) +{ + return env->banked_r13[bank_number(mode)]; +} + +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) +{ + switch (reg) { + case 0: /* APSR */ + return xpsr_read(env) & 0xf8000000; + case 1: /* IAPSR */ + return xpsr_read(env) & 0xf80001ff; + case 2: /* EAPSR */ + return xpsr_read(env) & 0xff00fc00; + case 3: /* xPSR */ + return xpsr_read(env) & 0xff00fdff; + case 5: /* IPSR */ + return xpsr_read(env) & 0x000001ff; + case 6: /* EPSR */ + return xpsr_read(env) & 0x0700fc00; + case 7: /* IEPSR */ + return xpsr_read(env) & 0x0700edff; + case 8: /* MSP */ + return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13]; + case 9: /* PSP */ + return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp; + case 16: /* PRIMASK */ + return (env->uncached_cpsr & CPSR_I) != 0; + case 17: /* FAULTMASK */ + return (env->uncached_cpsr & CPSR_F) != 0; + case 18: /* BASEPRI */ + case 19: /* BASEPRI_MAX */ + return env->v7m.basepri; + case 20: /* CONTROL */ + return env->v7m.control; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register read (%d)\n", reg); + return 0; + } +} + +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) +{ + switch (reg) { + case 0: /* APSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 1: /* IAPSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 2: /* EAPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 3: /* xPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 5: /* IPSR */ + /* IPSR bits are readonly. */ + break; + case 6: /* EPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 7: /* IEPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 8: /* MSP */ + if (env->v7m.current_sp) + env->v7m.other_sp = val; + else + env->regs[13] = val; + break; + case 9: /* PSP */ + if (env->v7m.current_sp) + env->regs[13] = val; + else + env->v7m.other_sp = val; + break; + case 16: /* PRIMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_I; + else + env->uncached_cpsr &= ~CPSR_I; + break; + case 17: /* FAULTMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_F; + else + env->uncached_cpsr &= ~CPSR_F; + break; + case 18: /* BASEPRI */ + env->v7m.basepri = val & 0xff; + break; + case 19: /* BASEPRI_MAX */ + val &= 0xff; + if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0)) + env->v7m.basepri = val; + break; + case 20: /* CONTROL */ + env->v7m.control = val & 3; + switch_v7m_sp(env, (val & 2) != 0); + break; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register write (%d)\n", reg); + return; + } +} + +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque) +{ + if (cpnum < 0 || cpnum > 14) { + cpu_abort(env, "Bad coprocessor number: %i\n", cpnum); + return; + } + + env->cp[cpnum].cp_read = cp_read; + env->cp[cpnum].cp_write = cp_write; + env->cp[cpnum].opaque = opaque; +} + +#endif + +/* Note that signed overflow is undefined in C. The following routines are + careful to use unsigned types where modulo arithmetic is required. + Failure to do so _will_ break on newer gcc. */ + +/* Signed saturating arithmetic. */ + +/* Perform 16-bit signed saturating addition. */ +static inline uint16_t add16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a + b; + if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating addition. */ +static inline uint8_t add8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a + b; + if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +/* Perform 16-bit signed saturating subtraction. */ +static inline uint16_t sub16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a - b; + if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating subtraction. */ +static inline uint8_t sub8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a - b; + if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); +#define PFX q + +#include "op_addsub.h" + +/* Unsigned saturating arithmetic. */ +static inline uint16_t add16_usat(uint16_t a, uint16_t b) +{ + uint16_t res; + res = a + b; + if (res < a) + res = 0xffff; + return res; +} + +static inline uint16_t sub16_usat(uint16_t a, uint16_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +static inline uint8_t add8_usat(uint8_t a, uint8_t b) +{ + uint8_t res; + res = a + b; + if (res < a) + res = 0xff; + return res; +} + +static inline uint8_t sub8_usat(uint8_t a, uint8_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); +#define PFX uq + +#include "op_addsub.h" + +/* Signed modulo arithmetic. */ +#define SARITH16(a, b, n, op) do { \ + int32_t sum; \ + sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ + RESULT(sum, n, 16); \ + if (sum >= 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SARITH8(a, b, n, op) do { \ + int32_t sum; \ + sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ + RESULT(sum, n, 8); \ + if (sum >= 0) \ + ge |= 1 << n; \ + } while(0) + + +#define ADD16(a, b, n) SARITH16(a, b, n, +) +#define SUB16(a, b, n) SARITH16(a, b, n, -) +#define ADD8(a, b, n) SARITH8(a, b, n, +) +#define SUB8(a, b, n) SARITH8(a, b, n, -) +#define PFX s +#define ARITH_GE + +#include "op_addsub.h" + +/* Unsigned modulo arithmetic. */ +#define ADD16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 1) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define ADD8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 1) \ + ge |= 1 << n; \ + } while(0) + +#define SUB16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SUB8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 0) \ + ge |= 1 << n; \ + } while(0) + +#define PFX u +#define ARITH_GE + +#include "op_addsub.h" + +/* Halved signed arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) +#define PFX sh + +#include "op_addsub.h" + +/* Halved unsigned arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define PFX uh + +#include "op_addsub.h" + +static inline uint8_t do_usad(uint8_t a, uint8_t b) +{ + if (a > b) + return a - b; + else + return b - a; +} + +/* Unsigned sum of absolute byte differences. */ +uint32_t HELPER(usad8)(uint32_t a, uint32_t b) +{ + uint32_t sum; + sum = do_usad(a, b); + sum += do_usad(a >> 8, b >> 8); + sum += do_usad(a >> 16, b >>16); + sum += do_usad(a >> 24, b >> 24); + return sum; +} + +/* For ARMv6 SEL instruction. */ +uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) +{ + uint32_t mask; + + mask = 0; + if (flags & 1) + mask |= 0xff; + if (flags & 2) + mask |= 0xff00; + if (flags & 4) + mask |= 0xff0000; + if (flags & 8) + mask |= 0xff000000; + return (a & mask) | (b & ~mask); +} + +uint32_t HELPER(logicq_cc)(uint64_t val) +{ + return (val >> 32) | (val != 0); +} + +/* VFP support. We follow the convention used for VFP instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to vfp form. */ +static inline int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) + target_bits |= 1; + if (host_bits & float_flag_divbyzero) + target_bits |= 2; + if (host_bits & float_flag_overflow) + target_bits |= 4; + if (host_bits & float_flag_underflow) + target_bits |= 8; + if (host_bits & float_flag_inexact) + target_bits |= 0x10; + return target_bits; +} + +uint32_t HELPER(vfp_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) + | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + i = get_float_exception_flags(&env->vfp.fp_status); + fpscr |= vfp_exceptbits_from_host(i); + return fpscr; +} + +/* Convert vfp exception flags to target form. */ +static inline int vfp_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & 1) + host_bits |= float_flag_invalid; + if (target_bits & 2) + host_bits |= float_flag_divbyzero; + if (target_bits & 4) + host_bits |= float_flag_overflow; + if (target_bits & 8) + host_bits |= float_flag_underflow; + if (target_bits & 0x10) + host_bits |= float_flag_inexact; + return host_bits; +} + +void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff); + env->vfp.vec_len = (val >> 16) & 7; + env->vfp.vec_stride = (val >> 20) & 3; + + changed ^= val; + if (changed & (3 << 22)) { + i = (val >> 22) & 3; + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_up; + break; + case 2: + i = float_round_down; + break; + case 3: + i = float_round_to_zero; + break; + } + set_float_rounding_mode(i, &env->vfp.fp_status); + } + if (changed & (1 << 24)) + set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); + if (changed & (1 << 25)) + set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); + + i = vfp_exceptbits_to_host((val >> 8) & 0x1f); + set_float_exception_flags(i, &env->vfp.fp_status); +} + +#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) + +#define VFP_BINOP(name) \ +float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \ +{ \ + return float32_ ## name (a, b, &env->vfp.fp_status); \ +} \ +float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \ +{ \ + return float64_ ## name (a, b, &env->vfp.fp_status); \ +} +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) +#undef VFP_BINOP + +float32 VFP_HELPER(neg, s)(float32 a) +{ + return float32_chs(a); +} + +float64 VFP_HELPER(neg, d)(float64 a) +{ + return float64_chs(a); +} + +float32 VFP_HELPER(abs, s)(float32 a) +{ + return float32_abs(a); +} + +float64 VFP_HELPER(abs, d)(float64 a) +{ + return float64_abs(a); +} + +float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env) +{ + return float32_sqrt(a, &env->vfp.fp_status); +} + +float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env) +{ + return float64_sqrt(a, &env->vfp.fp_status); +} + +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, type) \ +void VFP_HELPER(cmp, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} \ +void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} +DO_VFP_cmp(s, float32) +DO_VFP_cmp(d, float64) +#undef DO_VFP_cmp + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 vfp_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t vfp_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) +{ + return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) +{ + return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) +{ + return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) +{ + return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +/* Float to integer conversion. */ +float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +/* floating point conversion */ +float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->vfp.fp_status); +} + +float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->vfp.fp_status); +} + +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ +ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ + &env->vfp.fp_status); \ + return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \ +} \ +ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ + return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ + &env->vfp.fp_status)); \ +} + +VFP_CONV_FIX(sh, d, float64, int16, ) +VFP_CONV_FIX(sl, d, float64, int32, ) +VFP_CONV_FIX(uh, d, float64, uint16, u) +VFP_CONV_FIX(ul, d, float64, uint32, u) +VFP_CONV_FIX(sh, s, float32, int16, ) +VFP_CONV_FIX(sl, s, float32, int32, ) +VFP_CONV_FIX(uh, s, float32, uint16, u) +VFP_CONV_FIX(ul, s, float32, uint32, u) +#undef VFP_CONV_FIX + +/* Half precision conversions. */ +float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; + return float16_to_float32(a, ieee, s); +} + +uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; + return float32_to_float16(a, ieee, s); +} + +float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 two = int32_to_float32(2, s); + return float32_sub(two, float32_mul(a, b, s), s); +} + +float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 three = int32_to_float32(3, s); + return float32_sub(three, float32_mul(a, b, s), s); +} + +/* NEON helpers. */ + +/* TODO: The architecture specifies the value that the estimate functions + should return. We return the exact reciprocal/root instead. */ +float32 HELPER(recpe_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, a, s); +} + +float32 HELPER(rsqrte_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, float32_sqrt(a, s), s); +} + +uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_recpe_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_rsqrte_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +void HELPER(set_teecr)(CPUState *env, uint32_t val) +{ + val &= 1; + if (env->teecr != val) { + env->teecr = val; + tb_flush(env); + } +} diff --git a/qemu/qemu-git/target-arm/.svn/text-base/helpers.h.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/helpers.h.svn-base new file mode 100644 index 0000000..0d1bc47 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/helpers.h.svn-base @@ -0,0 +1,450 @@ +#include "def-helper.h" + +DEF_HELPER_1(clz, i32, i32) +DEF_HELPER_1(sxtb16, i32, i32) +DEF_HELPER_1(uxtb16, i32, i32) + +DEF_HELPER_2(add_setq, i32, i32, i32) +DEF_HELPER_2(add_saturate, i32, i32, i32) +DEF_HELPER_2(sub_saturate, i32, i32, i32) +DEF_HELPER_2(add_usaturate, i32, i32, i32) +DEF_HELPER_2(sub_usaturate, i32, i32, i32) +DEF_HELPER_1(double_saturate, i32, s32) +DEF_HELPER_2(sdiv, s32, s32, s32) +DEF_HELPER_2(udiv, i32, i32, i32) +DEF_HELPER_1(rbit, i32, i32) +DEF_HELPER_1(abs, i32, i32) + +#define PAS_OP(pfx) \ + DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr) + +PAS_OP(s) +PAS_OP(u) +#undef PAS_OP + +#define PAS_OP(pfx) \ + DEF_HELPER_2(pfx ## add8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## add16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \ + DEF_HELPER_2(pfx ## subaddx, i32, i32, i32) +PAS_OP(q) +PAS_OP(sh) +PAS_OP(uq) +PAS_OP(uh) +#undef PAS_OP + +DEF_HELPER_2(ssat, i32, i32, i32) +DEF_HELPER_2(usat, i32, i32, i32) +DEF_HELPER_2(ssat16, i32, i32, i32) +DEF_HELPER_2(usat16, i32, i32, i32) + +DEF_HELPER_2(usad8, i32, i32, i32) + +DEF_HELPER_1(logicq_cc, i32, i64) + +DEF_HELPER_3(sel_flags, i32, i32, i32, i32) +DEF_HELPER_1(exception, void, i32) +DEF_HELPER_0(wfi, void) + +DEF_HELPER_2(cpsr_write, void, i32, i32) +DEF_HELPER_0(cpsr_read, i32) + +DEF_HELPER_3(v7m_msr, void, env, i32, i32) +DEF_HELPER_2(v7m_mrs, i32, env, i32) + +DEF_HELPER_3(set_cp15, void, env, i32, i32) +DEF_HELPER_2(get_cp15, i32, env, i32) + +DEF_HELPER_3(set_cp, void, env, i32, i32) +DEF_HELPER_2(get_cp, i32, env, i32) + +DEF_HELPER_2(get_r13_banked, i32, env, i32) +DEF_HELPER_3(set_r13_banked, void, env, i32, i32) + +DEF_HELPER_1(get_user_reg, i32, i32) +DEF_HELPER_2(set_user_reg, void, i32, i32) + +DEF_HELPER_1(vfp_get_fpscr, i32, env) +DEF_HELPER_2(vfp_set_fpscr, void, env, i32) + +DEF_HELPER_3(vfp_adds, f32, f32, f32, env) +DEF_HELPER_3(vfp_addd, f64, f64, f64, env) +DEF_HELPER_3(vfp_subs, f32, f32, f32, env) +DEF_HELPER_3(vfp_subd, f64, f64, f64, env) +DEF_HELPER_3(vfp_muls, f32, f32, f32, env) +DEF_HELPER_3(vfp_muld, f64, f64, f64, env) +DEF_HELPER_3(vfp_divs, f32, f32, f32, env) +DEF_HELPER_3(vfp_divd, f64, f64, f64, env) +DEF_HELPER_1(vfp_negs, f32, f32) +DEF_HELPER_1(vfp_negd, f64, f64) +DEF_HELPER_1(vfp_abss, f32, f32) +DEF_HELPER_1(vfp_absd, f64, f64) +DEF_HELPER_2(vfp_sqrts, f32, f32, env) +DEF_HELPER_2(vfp_sqrtd, f64, f64, env) +DEF_HELPER_3(vfp_cmps, void, f32, f32, env) +DEF_HELPER_3(vfp_cmpd, void, f64, f64, env) +DEF_HELPER_3(vfp_cmpes, void, f32, f32, env) +DEF_HELPER_3(vfp_cmped, void, f64, f64, env) + +DEF_HELPER_2(vfp_fcvtds, f64, f32, env) +DEF_HELPER_2(vfp_fcvtsd, f32, f64, env) + +DEF_HELPER_2(vfp_uitos, f32, f32, env) +DEF_HELPER_2(vfp_uitod, f64, f32, env) +DEF_HELPER_2(vfp_sitos, f32, f32, env) +DEF_HELPER_2(vfp_sitod, f64, f32, env) + +DEF_HELPER_2(vfp_touis, f32, f32, env) +DEF_HELPER_2(vfp_touid, f32, f64, env) +DEF_HELPER_2(vfp_touizs, f32, f32, env) +DEF_HELPER_2(vfp_touizd, f32, f64, env) +DEF_HELPER_2(vfp_tosis, f32, f32, env) +DEF_HELPER_2(vfp_tosid, f32, f64, env) +DEF_HELPER_2(vfp_tosizs, f32, f32, env) +DEF_HELPER_2(vfp_tosizd, f32, f64, env) + +DEF_HELPER_3(vfp_toshs, f32, f32, i32, env) +DEF_HELPER_3(vfp_tosls, f32, f32, i32, env) +DEF_HELPER_3(vfp_touhs, f32, f32, i32, env) +DEF_HELPER_3(vfp_touls, f32, f32, i32, env) +DEF_HELPER_3(vfp_toshd, f64, f64, i32, env) +DEF_HELPER_3(vfp_tosld, f64, f64, i32, env) +DEF_HELPER_3(vfp_touhd, f64, f64, i32, env) +DEF_HELPER_3(vfp_tould, f64, f64, i32, env) +DEF_HELPER_3(vfp_shtos, f32, f32, i32, env) +DEF_HELPER_3(vfp_sltos, f32, f32, i32, env) +DEF_HELPER_3(vfp_uhtos, f32, f32, i32, env) +DEF_HELPER_3(vfp_ultos, f32, f32, i32, env) +DEF_HELPER_3(vfp_shtod, f64, f64, i32, env) +DEF_HELPER_3(vfp_sltod, f64, f64, i32, env) +DEF_HELPER_3(vfp_uhtod, f64, f64, i32, env) +DEF_HELPER_3(vfp_ultod, f64, f64, i32, env) + +DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env) +DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env) + +DEF_HELPER_3(recps_f32, f32, f32, f32, env) +DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env) +DEF_HELPER_2(recpe_f32, f32, f32, env) +DEF_HELPER_2(rsqrte_f32, f32, f32, env) +DEF_HELPER_2(recpe_u32, i32, i32, env) +DEF_HELPER_2(rsqrte_u32, i32, i32, env) +DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32) +DEF_HELPER_2(neon_add_saturate_u64, i64, i64, i64) +DEF_HELPER_2(neon_add_saturate_s64, i64, i64, i64) +DEF_HELPER_2(neon_sub_saturate_u64, i64, i64, i64) +DEF_HELPER_2(neon_sub_saturate_s64, i64, i64, i64) + +DEF_HELPER_2(add_cc, i32, i32, i32) +DEF_HELPER_2(adc_cc, i32, i32, i32) +DEF_HELPER_2(sub_cc, i32, i32, i32) +DEF_HELPER_2(sbc_cc, i32, i32, i32) + +DEF_HELPER_2(shl, i32, i32, i32) +DEF_HELPER_2(shr, i32, i32, i32) +DEF_HELPER_2(sar, i32, i32, i32) +DEF_HELPER_2(shl_cc, i32, i32, i32) +DEF_HELPER_2(shr_cc, i32, i32, i32) +DEF_HELPER_2(sar_cc, i32, i32, i32) +DEF_HELPER_2(ror_cc, i32, i32, i32) + +/* neon_helper.c */ +DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32) + +DEF_HELPER_2(neon_hadd_s8, i32, i32, i32) +DEF_HELPER_2(neon_hadd_u8, i32, i32, i32) +DEF_HELPER_2(neon_hadd_s16, i32, i32, i32) +DEF_HELPER_2(neon_hadd_u16, i32, i32, i32) +DEF_HELPER_2(neon_hadd_s32, s32, s32, s32) +DEF_HELPER_2(neon_hadd_u32, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32) +DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s8, i32, i32, i32) +DEF_HELPER_2(neon_hsub_u8, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s16, i32, i32, i32) +DEF_HELPER_2(neon_hsub_u16, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s32, s32, s32, s32) +DEF_HELPER_2(neon_hsub_u32, i32, i32, i32) + +DEF_HELPER_2(neon_cgt_u8, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s8, i32, i32, i32) +DEF_HELPER_2(neon_cgt_u16, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s16, i32, i32, i32) +DEF_HELPER_2(neon_cgt_u32, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s32, i32, i32, i32) +DEF_HELPER_2(neon_cge_u8, i32, i32, i32) +DEF_HELPER_2(neon_cge_s8, i32, i32, i32) +DEF_HELPER_2(neon_cge_u16, i32, i32, i32) +DEF_HELPER_2(neon_cge_s16, i32, i32, i32) +DEF_HELPER_2(neon_cge_u32, i32, i32, i32) +DEF_HELPER_2(neon_cge_s32, i32, i32, i32) + +DEF_HELPER_2(neon_min_u8, i32, i32, i32) +DEF_HELPER_2(neon_min_s8, i32, i32, i32) +DEF_HELPER_2(neon_min_u16, i32, i32, i32) +DEF_HELPER_2(neon_min_s16, i32, i32, i32) +DEF_HELPER_2(neon_min_u32, i32, i32, i32) +DEF_HELPER_2(neon_min_s32, i32, i32, i32) +DEF_HELPER_2(neon_max_u8, i32, i32, i32) +DEF_HELPER_2(neon_max_s8, i32, i32, i32) +DEF_HELPER_2(neon_max_u16, i32, i32, i32) +DEF_HELPER_2(neon_max_s16, i32, i32, i32) +DEF_HELPER_2(neon_max_u32, i32, i32, i32) +DEF_HELPER_2(neon_max_s32, i32, i32, i32) +DEF_HELPER_2(neon_pmin_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s16, i32, i32, i32) + +DEF_HELPER_2(neon_abd_u8, i32, i32, i32) +DEF_HELPER_2(neon_abd_s8, i32, i32, i32) +DEF_HELPER_2(neon_abd_u16, i32, i32, i32) +DEF_HELPER_2(neon_abd_s16, i32, i32, i32) +DEF_HELPER_2(neon_abd_u32, i32, i32, i32) +DEF_HELPER_2(neon_abd_s32, i32, i32, i32) + +DEF_HELPER_2(neon_shl_u8, i32, i32, i32) +DEF_HELPER_2(neon_shl_s8, i32, i32, i32) +DEF_HELPER_2(neon_shl_u16, i32, i32, i32) +DEF_HELPER_2(neon_shl_s16, i32, i32, i32) +DEF_HELPER_2(neon_shl_u32, i32, i32, i32) +DEF_HELPER_2(neon_shl_s32, i32, i32, i32) +DEF_HELPER_2(neon_shl_u64, i64, i64, i64) +DEF_HELPER_2(neon_shl_s64, i64, i64, i64) +DEF_HELPER_2(neon_rshl_u8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u64, i64, i64, i64) +DEF_HELPER_2(neon_rshl_s64, i64, i64, i64) +DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64) + +DEF_HELPER_2(neon_add_u8, i32, i32, i32) +DEF_HELPER_2(neon_add_u16, i32, i32, i32) +DEF_HELPER_2(neon_padd_u8, i32, i32, i32) +DEF_HELPER_2(neon_padd_u16, i32, i32, i32) +DEF_HELPER_2(neon_sub_u8, i32, i32, i32) +DEF_HELPER_2(neon_sub_u16, i32, i32, i32) +DEF_HELPER_2(neon_mul_u8, i32, i32, i32) +DEF_HELPER_2(neon_mul_u16, i32, i32, i32) +DEF_HELPER_2(neon_mul_p8, i32, i32, i32) + +DEF_HELPER_2(neon_tst_u8, i32, i32, i32) +DEF_HELPER_2(neon_tst_u16, i32, i32, i32) +DEF_HELPER_2(neon_tst_u32, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u8, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u16, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u32, i32, i32, i32) + +DEF_HELPER_1(neon_abs_s8, i32, i32) +DEF_HELPER_1(neon_abs_s16, i32, i32) +DEF_HELPER_1(neon_clz_u8, i32, i32) +DEF_HELPER_1(neon_clz_u16, i32, i32) +DEF_HELPER_1(neon_cls_s8, i32, i32) +DEF_HELPER_1(neon_cls_s16, i32, i32) +DEF_HELPER_1(neon_cls_s32, i32, i32) +DEF_HELPER_1(neon_cnt_u8, i32, i32) + +DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) + +DEF_HELPER_1(neon_narrow_u8, i32, i64) +DEF_HELPER_1(neon_narrow_u16, i32, i64) +DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64) +DEF_HELPER_1(neon_narrow_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_high_u16, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64) +DEF_HELPER_1(neon_widen_u8, i64, i32) +DEF_HELPER_1(neon_widen_s8, i64, i32) +DEF_HELPER_1(neon_widen_u16, i64, i32) +DEF_HELPER_1(neon_widen_s16, i64, i32) + +DEF_HELPER_2(neon_addl_u16, i64, i64, i64) +DEF_HELPER_2(neon_addl_u32, i64, i64, i64) +DEF_HELPER_2(neon_paddl_u16, i64, i64, i64) +DEF_HELPER_2(neon_paddl_u32, i64, i64, i64) +DEF_HELPER_2(neon_subl_u16, i64, i64, i64) +DEF_HELPER_2(neon_subl_u32, i64, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u64, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s64, i64, i32, i32) +DEF_HELPER_2(neon_mull_u8, i64, i32, i32) +DEF_HELPER_2(neon_mull_s8, i64, i32, i32) +DEF_HELPER_2(neon_mull_u16, i64, i32, i32) +DEF_HELPER_2(neon_mull_s16, i64, i32, i32) + +DEF_HELPER_1(neon_negl_u16, i64, i64) +DEF_HELPER_1(neon_negl_u32, i64, i64) +DEF_HELPER_1(neon_negl_u64, i64, i64) + +DEF_HELPER_2(neon_qabs_s8, i32, env, i32) +DEF_HELPER_2(neon_qabs_s16, i32, env, i32) +DEF_HELPER_2(neon_qabs_s32, i32, env, i32) +DEF_HELPER_2(neon_qneg_s8, i32, env, i32) +DEF_HELPER_2(neon_qneg_s16, i32, env, i32) +DEF_HELPER_2(neon_qneg_s32, i32, env, i32) + +DEF_HELPER_2(neon_min_f32, i32, i32, i32) +DEF_HELPER_2(neon_max_f32, i32, i32, i32) +DEF_HELPER_2(neon_abd_f32, i32, i32, i32) +DEF_HELPER_2(neon_add_f32, i32, i32, i32) +DEF_HELPER_2(neon_sub_f32, i32, i32, i32) +DEF_HELPER_2(neon_mul_f32, i32, i32, i32) +DEF_HELPER_2(neon_ceq_f32, i32, i32, i32) +DEF_HELPER_2(neon_cge_f32, i32, i32, i32) +DEF_HELPER_2(neon_cgt_f32, i32, i32, i32) +DEF_HELPER_2(neon_acge_f32, i32, i32, i32) +DEF_HELPER_2(neon_acgt_f32, i32, i32, i32) + +/* iwmmxt_helper.c */ +DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64) +DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64) + +#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ +DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \ + +DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) +DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) + +DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64) + +DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) + +DEF_IWMMXT_HELPER_SIZE_ENV(mins) +DEF_IWMMXT_HELPER_SIZE_ENV(minu) +DEF_IWMMXT_HELPER_SIZE_ENV(maxs) +DEF_IWMMXT_HELPER_SIZE_ENV(maxu) + +DEF_IWMMXT_HELPER_SIZE_ENV(subn) +DEF_IWMMXT_HELPER_SIZE_ENV(addn) +DEF_IWMMXT_HELPER_SIZE_ENV(subu) +DEF_IWMMXT_HELPER_SIZE_ENV(addu) +DEF_IWMMXT_HELPER_SIZE_ENV(subs) +DEF_IWMMXT_HELPER_SIZE_ENV(adds) + +DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64) + +DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64) + +DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32) +DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32) + +DEF_HELPER_1(iwmmxt_bcstb, i64, i32) +DEF_HELPER_1(iwmmxt_bcstw, i64, i32) +DEF_HELPER_1(iwmmxt_bcstl, i64, i32) + +DEF_HELPER_1(iwmmxt_addcb, i64, i64) +DEF_HELPER_1(iwmmxt_addcw, i64, i64) +DEF_HELPER_1(iwmmxt_addcl, i64, i64) + +DEF_HELPER_1(iwmmxt_msbb, i32, i64) +DEF_HELPER_1(iwmmxt_msbw, i32, i64) +DEF_HELPER_1(iwmmxt_msbl, i32, i64) + +DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32) + +DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64) + +DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) + +DEF_HELPER_2(set_teecr, void, env, i32) + +#include "def-helper.h" diff --git a/qemu/qemu-git/target-arm/.svn/text-base/iwmmxt_helper.c.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/iwmmxt_helper.c.svn-base new file mode 100644 index 0000000..3332f70 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/iwmmxt_helper.c.svn-base @@ -0,0 +1,681 @@ +/* + * iwMMXt micro operations for XScale. + * + * Copyright (c) 2007 OpenedHand, Ltd. + * Written by Andrzej Zaborowski + * Copyright (c) 2008 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +/* iwMMXt macros extracted from GNU gdb. */ + +/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ +#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n))) +#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n))) +#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n))) +#define SIMD64_SET(v, n) ((v != 0) << (32 + (n))) +/* Flags to pass as "n" above. */ +#define SIMD_NBIT -1 +#define SIMD_ZBIT -2 +#define SIMD_CBIT -3 +#define SIMD_VBIT -4 +/* Various status bit macros. */ +#define NBIT8(x) ((x) & 0x80) +#define NBIT16(x) ((x) & 0x8000) +#define NBIT32(x) ((x) & 0x80000000) +#define NBIT64(x) ((x) & 0x8000000000000000ULL) +#define ZBIT8(x) (((x) & 0xff) == 0) +#define ZBIT16(x) (((x) & 0xffff) == 0) +#define ZBIT32(x) (((x) & 0xffffffff) == 0) +#define ZBIT64(x) (x == 0) +/* Sign extension macros. */ +#define EXTEND8H(a) ((uint16_t) (int8_t) (a)) +#define EXTEND8(a) ((uint32_t) (int8_t) (a)) +#define EXTEND16(a) ((uint32_t) (int16_t) (a)) +#define EXTEND16S(a) ((int32_t) (int16_t) (a)) +#define EXTEND32(a) ((uint64_t) (int32_t) (a)) + +uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b) +{ + a = (( + EXTEND16S((a >> 0) & 0xffff) * EXTEND16S((b >> 0) & 0xffff) + + EXTEND16S((a >> 16) & 0xffff) * EXTEND16S((b >> 16) & 0xffff) + ) & 0xffffffff) | ((uint64_t) ( + EXTEND16S((a >> 32) & 0xffff) * EXTEND16S((b >> 32) & 0xffff) + + EXTEND16S((a >> 48) & 0xffff) * EXTEND16S((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_madduq)(uint64_t a, uint64_t b) +{ + a = (( + ((a >> 0) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff) + ) & 0xffffffff) | (( + ((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_sadb)(uint64_t a, uint64_t b) +{ +#define abs(x) (((x) >= 0) ? x : -x) +#define SADB(SHR) abs((int) ((a >> SHR) & 0xff) - (int) ((b >> SHR) & 0xff)) + return + SADB(0) + SADB(8) + SADB(16) + SADB(24) + + SADB(32) + SADB(40) + SADB(48) + SADB(56); +#undef SADB +} + +uint64_t HELPER(iwmmxt_sadw)(uint64_t a, uint64_t b) +{ +#define SADW(SHR) \ + abs((int) ((a >> SHR) & 0xffff) - (int) ((b >> SHR) & 0xffff)) + return SADW(0) + SADW(16) + SADW(32) + SADW(48); +#undef SADW +} + +uint64_t HELPER(iwmmxt_mulslw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mulshw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mululw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_muluhw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_macsw)(uint64_t a, uint64_t b) +{ +#define MACS(SHR) ( \ + EXTEND16((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff)) + return (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); +#undef MACS +} + +uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b) +{ +#define MACU(SHR) ( \ + (uint32_t) ((a >> SHR) & 0xffff) * \ + (uint32_t) ((b >> SHR) & 0xffff)) + return MACU(0) + MACU(16) + MACU(32) + MACU(48); +#undef MACU +} + +#define NZBIT8(x, i) \ + SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \ + SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i) +#define NZBIT16(x, i) \ + SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \ + SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i) +#define NZBIT32(x, i) \ + SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \ + SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i) +#define NZBIT64(x) \ + SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ + SIMD64_SET(ZBIT64(x), SIMD_ZBIT) +#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \ + (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \ + (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \ + (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffff) << 0) | \ + (((b >> SH0) & 0xffff) << 16) | \ + (((a >> SH2) & 0xffff) << 32) | \ + (((b >> SH2) & 0xffff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \ + NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffffffff) << 0) | \ + (((b >> SH0) & 0xffffffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xff) << 0) | \ + (((x >> SH1) & 0xff) << 16) | \ + (((x >> SH2) & 0xff) << 32) | \ + (((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xffff) << 0) | \ + (((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = (((x >> SH0) & 0xffffffff) << 0); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \ + ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \ + ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \ + ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \ + ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = EXTEND32((x >> SH0) & 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} +IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) +IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) + +#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ + CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \ + CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \ + CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ + CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \ + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tl, O, 0xffffffff) | \ + CMP(32, Tl, O, 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR) +IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==) +IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? a : b) & ((uint64_t) MASK << SHR)) +IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <) +IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <) +IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +) +#undef CMP +/* TODO Signed- and Unsigned-Saturation */ +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +) +IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -) +IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) +#undef CMP +#undef IWMMXT_OP_CMP + +#define AVGB(SHR) ((( \ + ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGB(r) \ +uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | \ + AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD8_SET(ZBIT8((a >> 0) & 0xff), SIMD_ZBIT, 0) | \ + SIMD8_SET(ZBIT8((a >> 8) & 0xff), SIMD_ZBIT, 1) | \ + SIMD8_SET(ZBIT8((a >> 16) & 0xff), SIMD_ZBIT, 2) | \ + SIMD8_SET(ZBIT8((a >> 24) & 0xff), SIMD_ZBIT, 3) | \ + SIMD8_SET(ZBIT8((a >> 32) & 0xff), SIMD_ZBIT, 4) | \ + SIMD8_SET(ZBIT8((a >> 40) & 0xff), SIMD_ZBIT, 5) | \ + SIMD8_SET(ZBIT8((a >> 48) & 0xff), SIMD_ZBIT, 6) | \ + SIMD8_SET(ZBIT8((a >> 56) & 0xff), SIMD_ZBIT, 7); \ + return a; \ +} +IWMMXT_OP_AVGB(0) +IWMMXT_OP_AVGB(1) +#undef IWMMXT_OP_AVGB +#undef AVGB + +#define AVGW(SHR) ((( \ + ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGW(r) \ +uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD16_SET(ZBIT16((a >> 0) & 0xffff), SIMD_ZBIT, 0) | \ + SIMD16_SET(ZBIT16((a >> 16) & 0xffff), SIMD_ZBIT, 1) | \ + SIMD16_SET(ZBIT16((a >> 32) & 0xffff), SIMD_ZBIT, 2) | \ + SIMD16_SET(ZBIT16((a >> 48) & 0xffff), SIMD_ZBIT, 3); \ + return a; \ +} +IWMMXT_OP_AVGW(0) +IWMMXT_OP_AVGW(1) +#undef IWMMXT_OP_AVGW +#undef AVGW + +uint64_t HELPER(iwmmxt_msadb)(uint64_t a, uint64_t b) +{ + a = ((((a >> 0 ) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)) & 0xffffffff) | + ((((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_align)(uint64_t a, uint64_t b, uint32_t n) +{ + a >>= n << 3; + a |= b << (64 - (n << 3)); + return a; +} + +uint64_t HELPER(iwmmxt_insr)(uint64_t x, uint32_t a, uint32_t b, uint32_t n) +{ + x &= ~((uint64_t) b << n); + x |= (uint64_t) (a & b) << n; + return x; +} + +uint32_t HELPER(iwmmxt_setpsr_nz)(uint64_t x) +{ + return SIMD64_SET((x == 0), SIMD_ZBIT) | + SIMD64_SET((x & (1ULL << 63)), SIMD_NBIT); +} + +uint64_t HELPER(iwmmxt_bcstb)(uint32_t arg) +{ + arg &= 0xff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 8 ) | + ((uint64_t) arg << 16) | ((uint64_t) arg << 24) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 40) | + ((uint64_t) arg << 48) | ((uint64_t) arg << 56); +} + +uint64_t HELPER(iwmmxt_bcstw)(uint32_t arg) +{ + arg &= 0xffff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 16) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 48); +} + +uint64_t HELPER(iwmmxt_bcstl)(uint32_t arg) +{ + return arg | ((uint64_t) arg << 32); +} + +uint64_t HELPER(iwmmxt_addcb)(uint64_t x) +{ + return + ((x >> 0) & 0xff) + ((x >> 8) & 0xff) + + ((x >> 16) & 0xff) + ((x >> 24) & 0xff) + + ((x >> 32) & 0xff) + ((x >> 40) & 0xff) + + ((x >> 48) & 0xff) + ((x >> 56) & 0xff); +} + +uint64_t HELPER(iwmmxt_addcw)(uint64_t x) +{ + return + ((x >> 0) & 0xffff) + ((x >> 16) & 0xffff) + + ((x >> 32) & 0xffff) + ((x >> 48) & 0xffff); +} + +uint64_t HELPER(iwmmxt_addcl)(uint64_t x) +{ + return (x & 0xffffffff) + (x >> 32); +} + +uint32_t HELPER(iwmmxt_msbb)(uint64_t x) +{ + return + ((x >> 7) & 0x01) | ((x >> 14) & 0x02) | + ((x >> 21) & 0x04) | ((x >> 28) & 0x08) | + ((x >> 35) & 0x10) | ((x >> 42) & 0x20) | + ((x >> 49) & 0x40) | ((x >> 56) & 0x80); +} + +uint32_t HELPER(iwmmxt_msbw)(uint64_t x) +{ + return + ((x >> 15) & 0x01) | ((x >> 30) & 0x02) | + ((x >> 45) & 0x04) | ((x >> 52) & 0x08); +} + +uint32_t HELPER(iwmmxt_msbl)(uint64_t x) +{ + return ((x >> 31) & 0x01) | ((x >> 62) & 0x02); +} + +/* FIXME: Split wCASF setting into a separate op to avoid env use. */ +uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) >> n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) >> n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n) +{ + x >>= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) << n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) << n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x << n) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << n); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n) +{ + x <<= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) | + ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) | + ((uint64_t) ((EXTEND16(x >> 32) >> n) & 0xffff) << 32) | + ((uint64_t) ((EXTEND16(x >> 48) >> n) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) | + (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (int64_t) x >> n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((((x & (0xffffll << 0)) >> n) | + ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) | + ((((x & (0xffffll << 16)) >> n) | + ((x & (0xffffll << 16)) << (16 - n))) & (0xffffll << 16)) | + ((((x & (0xffffll << 32)) >> n) | + ((x & (0xffffll << 32)) << (16 - n))) & (0xffffll << 32)) | + ((((x & (0xffffll << 48)) >> n) | + ((x & (0xffffll << 48)) << (16 - n))) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)) | + ((x << (32 - n)) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << (32 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (x >> n) | (x << (64 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) | + (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) | + (((x >> ((n << 0) & 0x30)) & 0xffff) << 32) | + (((x >> ((n >> 2) & 0x30)) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +/* TODO: Unsigned-Saturation */ +uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +/* TODO: Signed-Saturation */ +uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +uint64_t HELPER(iwmmxt_muladdsl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + ((int32_t) EXTEND32(a) * (int32_t) EXTEND32(b)); +} + +uint64_t HELPER(iwmmxt_muladdsw)(uint64_t c, uint32_t a, uint32_t b) +{ + c += EXTEND32(EXTEND16S((a >> 0) & 0xffff) * + EXTEND16S((b >> 0) & 0xffff)); + c += EXTEND32(EXTEND16S((a >> 16) & 0xffff) * + EXTEND16S((b >> 16) & 0xffff)); + return c; +} + +uint64_t HELPER(iwmmxt_muladdswl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + (EXTEND32(EXTEND16S(a & 0xffff) * + EXTEND16S(b & 0xffff))); +} diff --git a/qemu/qemu-git/target-arm/.svn/text-base/neon_helper.c.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/neon_helper.c.svn-base new file mode 100644 index 0000000..5e6452b --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/neon_helper.c.svn-base @@ -0,0 +1,1459 @@ +/* + * ARM NEON vector operations. + * + * Copyright (c) 2007, 2008 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GNU GPL v2. + */ +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q + +static float_status neon_float_status; +#define NFS &neon_float_status + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +#define NEON_TYPE1(name, type) \ +typedef struct \ +{ \ + type v1; \ +} neon_##name; +#ifdef HOST_WORDS_BIGENDIAN +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v2; \ + type v1; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v4; \ + type v3; \ + type v2; \ + type v1; \ +} neon_##name; +#else +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ + type v3; \ + type v4; \ +} neon_##name; +#endif + +NEON_TYPE4(s8, int8_t) +NEON_TYPE4(u8, uint8_t) +NEON_TYPE2(s16, int16_t) +NEON_TYPE2(u16, uint16_t) +NEON_TYPE1(s32, int32_t) +NEON_TYPE1(u32, uint32_t) +#undef NEON_TYPE4 +#undef NEON_TYPE2 +#undef NEON_TYPE1 + +/* Copy from a uint32_t to a vector structure type. */ +#define NEON_UNPACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.i = (val); \ + dest = conv_u.v; \ + } while(0) + +/* Copy from a vector structure type to a uint32_t. */ +#define NEON_PACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.v = (val); \ + dest = conv_u.i; \ + } while(0) + +#define NEON_DO1 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); +#define NEON_DO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); +#define NEON_DO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \ + NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \ + NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4); + +#define NEON_VOP_BODY(vtype, n) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_DO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +#define NEON_VOP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +#define NEON_VOP_ENV(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +/* Pairwise operations. */ +/* For 32-bit elements each segment only contains a single element, so + the elementwise and pairwise operations are the same. */ +#define NEON_PDO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2); +#define NEON_PDO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \ + NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \ + NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \ + +#define NEON_POP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_PDO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +/* Unary operators. */ +#define NEON_VOP1(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg) \ +{ \ + vtype vsrc1; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg); \ + NEON_DO##n; \ + NEON_PACK(vtype, arg, vdest); \ + return arg; \ +} + + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qadd_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qadd_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 > 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qadd_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qadd_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = 0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qsub_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qsub_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 < 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qsub_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qsub_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 +NEON_VOP(hadd_s8, neon_s8, 4) +NEON_VOP(hadd_u8, neon_u8, 4) +NEON_VOP(hadd_s16, neon_s16, 2) +NEON_VOP(hadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_hadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1 +NEON_VOP(rhadd_s8, neon_s8, 4) +NEON_VOP(rhadd_u8, neon_u8, 4) +NEON_VOP(rhadd_s16, neon_s16, 2) +NEON_VOP(rhadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_rhadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_rhadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1 +NEON_VOP(hsub_s8, neon_s8, 4) +NEON_VOP(hsub_u8, neon_u8, 4) +NEON_VOP(hsub_s16, neon_s16, 2) +NEON_VOP(hsub_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hsub_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 +NEON_VOP(cgt_s8, neon_s8, 4) +NEON_VOP(cgt_u8, neon_u8, 4) +NEON_VOP(cgt_s16, neon_s16, 2) +NEON_VOP(cgt_u16, neon_u16, 2) +NEON_VOP(cgt_s32, neon_s32, 1) +NEON_VOP(cgt_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 +NEON_VOP(cge_s8, neon_s8, 4) +NEON_VOP(cge_u8, neon_u8, 4) +NEON_VOP(cge_s16, neon_s16, 2) +NEON_VOP(cge_u16, neon_u16, 2) +NEON_VOP(cge_s32, neon_s32, 1) +NEON_VOP(cge_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 +NEON_VOP(min_s8, neon_s8, 4) +NEON_VOP(min_u8, neon_u8, 4) +NEON_VOP(min_s16, neon_s16, 2) +NEON_VOP(min_u16, neon_u16, 2) +NEON_VOP(min_s32, neon_s32, 1) +NEON_VOP(min_u32, neon_u32, 1) +NEON_POP(pmin_s8, neon_s8, 4) +NEON_POP(pmin_u8, neon_u8, 4) +NEON_POP(pmin_s16, neon_s16, 2) +NEON_POP(pmin_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2 +NEON_VOP(max_s8, neon_s8, 4) +NEON_VOP(max_u8, neon_u8, 4) +NEON_VOP(max_s16, neon_s16, 2) +NEON_VOP(max_u16, neon_u16, 2) +NEON_VOP(max_s32, neon_s32, 1) +NEON_VOP(max_u32, neon_u32, 1) +NEON_POP(pmax_s8, neon_s8, 4) +NEON_POP(pmax_u8, neon_u8, 4) +NEON_POP(pmax_s16, neon_s16, 2) +NEON_POP(pmax_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) \ + dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) +NEON_VOP(abd_s8, neon_s8, 4) +NEON_VOP(abd_u8, neon_u8, 4) +NEON_VOP(abd_s16, neon_s16, 2) +NEON_VOP(abd_u16, neon_u16, 2) +NEON_VOP(abd_s32, neon_s32, 1) +NEON_VOP(abd_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8 || \ + tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_u8, neon_u8, 4) +NEON_VOP(shl_u16, neon_u16, 2) +NEON_VOP(shl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64 || shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (sizeof(src1) * 8 - 1); \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_s8, neon_s8, 4) +NEON_VOP(shl_s16, neon_s16, 2) +NEON_VOP(shl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift <= -64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (sizeof(src1) * 8 - 1); \ + } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + dest++; \ + dest >>= 1; \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_s8, neon_s8, 4) +NEON_VOP(rshl_s16, neon_s16, 2) +NEON_VOP(rshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift < -64) { + val >>= 63; + } else if (shift == -63) { + val >>= 63; + val++; + val >>= 1; + } else if (shift < 0) { + val = (val + ((int64_t)1 << (-1 - shift))) >> -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8 || \ + tmp < -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_u8, neon_u8, 4) +NEON_VOP(rshl_u16, neon_u16, 2) +NEON_VOP(rshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + if (shift >= 64 || shift < 64) { + val = 0; + } else if (shift == -64) { + /* Rounding a 1-bit result just preserves that bit. */ + val >>= 63; + } if (shift < 0) { + val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift; + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + if (src1) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = 0; \ + } \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_u8, neon_u8, 4) +NEON_VOP_ENV(qshl_u16, neon_u16, 2) +NEON_VOP_ENV(qshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64) { + if (val) { + val = ~(uint64_t)0; + SET_QC(); + } else { + val = 0; + } + } else if (shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~(uint64_t)0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + if (src1) \ + SET_QC(); \ + dest = src1 >> 31; \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> 31; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src2 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_s8, neon_s8, 4) +NEON_VOP_ENV(qshl_s16, neon_s16, 2) +NEON_VOP_ENV(qshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + if (val) { + SET_QC(); + val = (val >> 63) & ~SIGNBIT64; + } + } else if (shift <= 64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + int64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = (tmp >> 63) ^ ~SIGNBIT64; + } + } + return val; +} + + +/* FIXME: This is wrong. */ +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_u8, neon_u8, 4) +NEON_VOP_ENV(qrshl_u16, neon_u16, 2) +NEON_VOP_ENV(qrshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { \ + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src1 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_s8, neon_s8, 4) +NEON_VOP_ENV(qrshl_s16, neon_s16, 2) +NEON_VOP_ENV(qrshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { + int64_t tmp = val;; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = tmp >> 31; + } + } + return val; +} + +uint32_t HELPER(neon_add_u8)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80808080u; + a &= ~0x80808080u; + b &= ~0x80808080u; + return (a + b) ^ mask; +} + +uint32_t HELPER(neon_add_u16)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80008000u; + a &= ~0x80008000u; + b &= ~0x80008000u; + return (a + b) ^ mask; +} + +#define NEON_FN(dest, src1, src2) dest = src1 + src2 +NEON_POP(padd_u8, neon_u8, 4) +NEON_POP(padd_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 - src2 +NEON_VOP(sub_u8, neon_u8, 4) +NEON_VOP(sub_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 * src2 +NEON_VOP(mul_u8, neon_u8, 4) +NEON_VOP(mul_u16, neon_u16, 2) +#undef NEON_FN + +/* Polynomial multiplication is like integer multiplication except the + partial products are XORed, not added. */ +uint32_t HELPER(neon_mul_p8)(uint32_t op1, uint32_t op2) +{ + uint32_t mask; + uint32_t result; + result = 0; + while (op1) { + mask = 0; + if (op1 & 1) + mask |= 0xff; + if (op1 & (1 << 8)) + mask |= (0xff << 8); + if (op1 & (1 << 16)) + mask |= (0xff << 16); + if (op1 & (1 << 24)) + mask |= (0xff << 24); + result ^= op2 & mask; + op1 = (op1 >> 1) & 0x7f7f7f7f; + op2 = (op2 << 1) & 0xfefefefe; + } + return result; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0 +NEON_VOP(tst_u8, neon_u8, 4) +NEON_VOP(tst_u16, neon_u16, 2) +NEON_VOP(tst_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 +NEON_VOP(ceq_u8, neon_u8, 4) +NEON_VOP(ceq_u16, neon_u16, 2) +NEON_VOP(ceq_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src +NEON_VOP1(abs_s8, neon_s8, 4) +NEON_VOP1(abs_s16, neon_s16, 2) +#undef NEON_FN + +/* Count Leading Sign/Zero Bits. */ +static inline int do_clz8(uint8_t x) +{ + int n; + for (n = 8; x; n--) + x >>= 1; + return n; +} + +static inline int do_clz16(uint16_t x) +{ + int n; + for (n = 16; x; n--) + x >>= 1; + return n; +} + +#define NEON_FN(dest, src, dummy) dest = do_clz8(src) +NEON_VOP1(clz_u8, neon_u8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16(src) +NEON_VOP1(clz_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz8((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s8, neon_s8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s16, neon_s16, 2) +#undef NEON_FN + +uint32_t HELPER(neon_cls_s32)(uint32_t x) +{ + int count; + if ((int32_t)x < 0) + x = ~x; + for (count = 32; x; count--) + x = x >> 1; + return count - 1; +} + +/* Bit count. */ +uint32_t HELPER(neon_cnt_u8)(uint32_t x) +{ + x = (x & 0x55555555) + ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f); + return x; +} + +#define NEON_QDMULH16(dest, src1, src2, round) do { \ + uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT) { \ + SET_QC(); \ + tmp = (tmp >> 31) ^ ~SIGNBIT; \ + } \ + tmp <<= 1; \ + if (round) { \ + int32_t old = tmp; \ + tmp += 1 << 15; \ + if ((int32_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT - 1; \ + } \ + } \ + dest = tmp >> 16; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s16, neon_s16, 2) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_QDMULH16 + +#define NEON_QDMULH32(dest, src1, src2, round) do { \ + uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \ + SET_QC(); \ + tmp = (tmp >> 63) ^ ~SIGNBIT64; \ + } else { \ + tmp <<= 1; \ + } \ + if (round) { \ + int64_t old = tmp; \ + tmp += (int64_t)1 << 31; \ + if ((int64_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT64 - 1; \ + } \ + } \ + dest = tmp >> 32; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s32, neon_s32, 1) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1) +#undef NEON_FN +#undef NEON_QDMULH32 + +uint32_t HELPER(neon_narrow_u8)(uint64_t x) +{ + return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u) + | ((x >> 24) & 0xff000000u); +} + +uint32_t HELPER(neon_narrow_u16)(uint64_t x) +{ + return (x & 0xffffu) | ((x >> 16) & 0xffff0000u); +} + +uint32_t HELPER(neon_narrow_high_u8)(uint64_t x) +{ + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_high_u16)(uint64_t x) +{ + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_round_high_u8)(uint64_t x) +{ + x &= 0xff80ff80ff80ff80ull; + x += 0x0080008000800080ull; + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x) +{ + x &= 0xffff8000ffff8000ull; + x += 0x0000800000008000ull; + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x) +{ + uint16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s > 0xff) { \ + d = 0xff; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x) +{ + int16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s != (int8_t)s) { \ + d = (s >> 15) ^ 0x7f; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x) +{ + uint32_t high; + uint32_t low; + low = x; + if (low > 0xffff) { + low = 0xffff; + SET_QC(); + } + high = x >> 32; + if (high > 0xffff) { + high = 0xffff; + SET_QC(); + } + return low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x) +{ + int32_t low; + int32_t high; + low = x; + if (low != (int16_t)low) { + low = (low >> 31) ^ 0x7fff; + SET_QC(); + } + high = x >> 32; + if (high != (int16_t)high) { + high = (high >> 31) ^ 0x7fff; + SET_QC(); + } + return (uint16_t)low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x) +{ + if (x > 0xffffffffu) { + SET_QC(); + return 0xffffffffu; + } + return x; +} + +uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x) +{ + if ((int64_t)x != (int32_t)x) { + SET_QC(); + return (x >> 63) ^ 0x7fffffff; + } + return x; +} + +uint64_t HELPER(neon_widen_u8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint8_t)x; + tmp = (uint8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_s8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint16_t)(int8_t)x; + tmp = (uint16_t)(int8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint16_t)(int8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint16_t)(int8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_u16)(uint32_t x) +{ + uint64_t high = (uint16_t)(x >> 16); + return ((uint16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_widen_s16)(uint32_t x) +{ + uint64_t high = (int16_t)(x >> 16); + return ((uint32_t)(int16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000800080008000ull; + a &= ~0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000000080000000ull; + a &= ~0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_paddl_u16)(uint64_t a, uint64_t b) +{ + uint64_t tmp; + uint64_t tmp2; + + tmp = a & 0x0000ffff0000ffffull; + tmp += (a >> 16) & 0x0000ffff0000ffffull; + tmp2 = b & 0xffff0000ffff0000ull; + tmp2 += (b << 16) & 0xffff0000ffff0000ull; + return ( tmp & 0xffff) + | ((tmp >> 16) & 0xffff0000ull) + | ((tmp2 << 16) & 0xffff00000000ull) + | ( tmp2 & 0xffff000000000000ull); +} + +uint64_t HELPER(neon_paddl_u32)(uint64_t a, uint64_t b) +{ + uint32_t low = a + (a >> 32); + uint32_t high = b + (b >> 32); + return low + ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000800080008000ull; + a |= 0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000000080000000ull; + a |= 0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b) +{ + uint32_t x, y; + uint32_t low, high; + + x = a; + y = b; + low = x + y; + if (((low ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + low = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + x = a >> 32; + y = b >> 32; + high = x + y; + if (((high ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + high = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + return low | ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b) +{ + uint64_t result; + + result = a + b; + if (((result ^ a) & SIGNBIT64) && !((a ^ b) & SIGNBIT64)) { + SET_QC(); + result = ((int64_t)a >> 63) ^ ~SIGNBIT64; + } + return result; +} + +#define DO_ABD(dest, x, y, type) do { \ + type tmp_x = x; \ + type tmp_y = y; \ + dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ + } while(0) + +uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint8_t); + DO_ABD(tmp, a >> 8, b >> 8, uint8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, uint8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, uint8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int8_t); + DO_ABD(tmp, a >> 8, b >> 8, int8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, int8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, int8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint16_t); + DO_ABD(tmp, a >> 16, b >> 16, uint16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int16_t); + DO_ABD(tmp, a >> 16, b >> 16, int16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, uint32_t); + return result; +} + +uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, int32_t); + return result; +} +#undef DO_ABD + +/* Widening multiply. Named type is the source type. */ +#define DO_MULL(dest, x, y, type1, type2) do { \ + type1 tmp_x = x; \ + type1 tmp_y = y; \ + dest = (type2)((type2)tmp_x * (type2)tmp_y); \ + } while(0) + +uint64_t HELPER(neon_mull_u8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, uint8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, uint8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, uint8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_s8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, int8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, int8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, int8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, uint16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_mull_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, int16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_negl_u16)(uint64_t x) +{ + uint16_t tmp; + uint64_t result; + result = (uint16_t)-x; + tmp = -(x >> 16); + result |= (uint64_t)tmp << 16; + tmp = -(x >> 32); + result |= (uint64_t)tmp << 32; + tmp = -(x >> 48); + result |= (uint64_t)tmp << 48; + return result; +} + +#include +uint64_t HELPER(neon_negl_u32)(uint64_t x) +{ + uint32_t low = -x; + uint32_t high = -(x >> 32); + return low | ((uint64_t)high << 32); +} + +/* FIXME: There should be a native op for this. */ +uint64_t HELPER(neon_negl_u64)(uint64_t x) +{ + return -x; +} + +/* Saturnating sign manuipulation. */ +/* ??? Make these use NEON_VOP1 */ +#define DO_QABS8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QABS8(vec.v1); + DO_QABS8(vec.v2); + DO_QABS8(vec.v3); + DO_QABS8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QABS8 + +#define DO_QNEG8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QNEG8(vec.v1); + DO_QNEG8(vec.v2); + DO_QNEG8(vec.v3); + DO_QNEG8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QNEG8 + +#define DO_QABS16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QABS16(vec.v1); + DO_QABS16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QABS16 + +#define DO_QNEG16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QNEG16(vec.v1); + DO_QNEG16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QNEG16 + +uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else if ((int32_t)x < 0) { + x = -x; + } + return x; +} + +uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else { + x = -x; + } + return x; +} + +/* NEON Float helpers. */ +uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b; +} + +uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b; +} + +uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) + ? float32_sub(f0, f1, NFS) + : float32_sub(f1, f0, NFS)); +} + +uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS)); +} + +/* Floating point comparisons produce an integer result. */ +#define NEON_VOP_FCMP(name, cmp) \ +uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \ +{ \ + if (float32_compare_quiet(vfp_itos(a), vfp_itos(b), NFS) cmp 0) \ + return ~0; \ + else \ + return 0; \ +} + +NEON_VOP_FCMP(ceq_f32, ==) +NEON_VOP_FCMP(cge_f32, >=) +NEON_VOP_FCMP(cgt_f32, >) + +uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0; +} + +uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0; +} diff --git a/qemu/qemu-git/target-arm/.svn/text-base/op_addsub.h.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/op_addsub.h.svn-base new file mode 100644 index 0000000..29f77ba --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/op_addsub.h.svn-base @@ -0,0 +1,103 @@ +/* + * ARMv6 integer SIMD operations. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#ifdef ARITH_GE +#define GE_ARG , void *gep +#define DECLARE_GE uint32_t ge = 0 +#define SET_GE *(uint32_t *)gep = ge +#else +#define GE_ARG +#define DECLARE_GE do{}while(0) +#define SET_GE do{}while(0) +#endif + +#define RESULT(val, n, width) \ + res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width) + +uint32_t HELPER(glue(PFX,add16))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,add8))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD8(a, b, 0); + ADD8(a >> 8, b >> 8, 1); + ADD8(a >> 16, b >> 16, 2); + ADD8(a >> 24, b >> 24, 3); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,sub16))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,sub8))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB8(a, b, 0); + SUB8(a >> 8, b >> 8, 1); + SUB8(a >> 16, b >> 16, 2); + SUB8(a >> 24, b >> 24, 3); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +#undef GE_ARG +#undef DECLARE_GE +#undef SET_GE +#undef RESULT + +#undef ARITH_GE +#undef PFX +#undef ADD16 +#undef SUB16 +#undef ADD8 +#undef SUB8 diff --git a/qemu/qemu-git/target-arm/.svn/text-base/op_helper.c.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/op_helper.c.svn-base new file mode 100644 index 0000000..9b1a014 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/op_helper.c.svn-base @@ -0,0 +1,489 @@ +/* + * ARM helper routines + * + * Copyright (c) 2005-2007 CodeSourcery, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "exec.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + +/* thread support */ + +static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, + uint32_t rn, uint32_t maxindex) +{ + uint32_t val; + uint32_t tmp; + int index; + int shift; + uint64_t *table; + table = (uint64_t *)&env->vfp.regs[rn]; + val = 0; + for (shift = 0; shift < 32; shift += 8) { + index = (ireg >> shift) & 0xff; + if (index < maxindex) { + tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff; + val |= tmp << shift; + } else { + val |= def & (0xff << shift); + } + } + return val; +} + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); + if (unlikely(ret)) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, NULL); + } + } + raise_exception(env->exception_index); + } + env = saved_env; +} +#endif + +/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating + instructions into helper.c */ +uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) + env->QF = 1; + return res; +} + +uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(double_saturate)(int32_t val) +{ + uint32_t res; + if (val >= 0x40000000) { + res = ~SIGNBIT; + env->QF = 1; + } else if (val <= (int32_t)0xc0000000) { + res = SIGNBIT; + env->QF = 1; + } else { + res = val << 1; + } + return res; +} + +uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (res < a) { + env->QF = 1; + res = ~0; + } + return res; +} + +uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (res > a) { + env->QF = 1; + res = 0; + } + return res; +} + +/* Signed saturation. */ +static inline uint32_t do_ssat(int32_t val, int shift) +{ + int32_t top; + uint32_t mask; + + top = val >> shift; + mask = (1u << shift) - 1; + if (top > 0) { + env->QF = 1; + return mask; + } else if (top < -1) { + env->QF = 1; + return ~mask; + } + return val; +} + +/* Unsigned saturation. */ +static inline uint32_t do_usat(int32_t val, int shift) +{ + uint32_t max; + + max = (1u << shift) - 1; + if (val < 0) { + env->QF = 1; + return 0; + } else if (val > max) { + env->QF = 1; + return max; + } + return val; +} + +/* Signed saturate. */ +uint32_t HELPER(ssat)(uint32_t x, uint32_t shift) +{ + return do_ssat(x, shift); +} + +/* Dual halfword signed saturate. */ +uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_ssat((int16_t)x, shift); + res |= do_ssat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +/* Unsigned saturate. */ +uint32_t HELPER(usat)(uint32_t x, uint32_t shift) +{ + return do_usat(x, shift); +} + +/* Dual halfword unsigned saturate. */ +uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_usat((int16_t)x, shift); + res |= do_usat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +void HELPER(wfi)(void) +{ + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(); +} + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(); +} + +uint32_t HELPER(cpsr_read)(void) +{ + return cpsr_read(env) & ~CPSR_EXEC; +} + +void HELPER(cpsr_write)(uint32_t val, uint32_t mask) +{ + cpsr_write(env, val, mask); +} + +/* Access to user mode registers from privileged modes. */ +uint32_t HELPER(get_user_reg)(uint32_t regno) +{ + uint32_t val; + + if (regno == 13) { + val = env->banked_r13[0]; + } else if (regno == 14) { + val = env->banked_r14[0]; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + val = env->usr_regs[regno - 8]; + } else { + val = env->regs[regno]; + } + return val; +} + +void HELPER(set_user_reg)(uint32_t regno, uint32_t val) +{ + if (regno == 13) { + env->banked_r13[0] = val; + } else if (regno == 14) { + env->banked_r14[0] = val; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + env->usr_regs[regno - 8] = val; + } else { + env->regs[regno] = val; + } +} + +/* ??? Flag setting arithmetic is awkward because we need to do comparisons. + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a + b; + env->NF = env->ZF = result; + env->CF = result < a; + env->VF = (a ^ b ^ -1) & (a ^ result); + return result; +} + +uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a + b; + env->CF = result < a; + } else { + result = a + b + 1; + env->CF = result <= a; + } + env->VF = (a ^ b ^ -1) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a - b; + env->NF = env->ZF = result; + env->CF = a >= b; + env->VF = (a ^ b) & (a ^ result); + return result; +} + +uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a - b - 1; + env->CF = a > b; + } else { + result = a - b; + env->CF = a >= b; + } + env->VF = (a ^ b) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +/* Similarly for variable shift instructions. */ + +uint32_t HELPER(shl)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return x << shift; +} + +uint32_t HELPER(shr)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return (uint32_t)x >> shift; +} + +uint32_t HELPER(sar)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + shift = 31; + return (int32_t)x >> shift; +} + +uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = x & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (32 - shift)) & 1; + return x << shift; + } + return x; +} + +uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = (x >> 31) & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return x >> shift; + } + return x; +} + +uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + env->CF = (x >> 31) & 1; + return (int32_t)x >> 31; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return (int32_t)x >> shift; + } + return x; +} + +uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) +{ + int shift1, shift; + shift1 = i & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) + env->CF = (x >> 31) & 1; + return x; + } else { + env->CF = (x >> (shift - 1)) & 1; + return ((uint32_t)x >> shift) | (x << (32 - shift)); + } +} + +uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (res < src1) { + env->QF = 1; + res = ~(uint64_t)0; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 - src2; + if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + if (src1 < src2) { + env->QF = 1; + res = 0; + } else { + res = src1 - src2; + } + return res; +} diff --git a/qemu/qemu-git/target-arm/.svn/text-base/translate.c.svn-base b/qemu/qemu-git/target-arm/.svn/text-base/translate.c.svn-base new file mode 100644 index 0000000..5cf3e06 --- /dev/null +++ b/qemu/qemu-git/target-arm/.svn/text-base/translate.c.svn-base @@ -0,0 +1,9254 @@ +/* + * ARM translation + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005-2007 CodeSourcery + * Copyright (c) 2007 OpenedHand, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#include "helpers.h" +#define GEN_HELPER 1 +#include "helpers.h" + +#define ENABLE_ARCH_5J 0 +#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) +#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) +#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) +#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) + +#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0) + +/* internal defines */ +typedef struct DisasContext { + target_ulong pc; + int is_jmp; + /* Nonzero if this instruction has been conditionally skipped. */ + int condjmp; + /* The label that will be jumped to when the instruction is skipped. */ + int condlabel; + /* Thumb-2 condtional execution bits. */ + int condexec_mask; + int condexec_cond; + struct TranslationBlock *tb; + int singlestep_enabled; + int thumb; +#if !defined(CONFIG_USER_ONLY) + int user; +#endif +} DisasContext; + +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) (s->user) +#endif + +/* These instructions trap after executing, so defer them until after the + conditional executions state has been updated. */ +#define DISAS_WFI 4 +#define DISAS_SWI 5 + +static TCGv_ptr cpu_env; +/* We reuse the same 64-bit temporaries for efficiency. */ +static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; +static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_exclusive_addr; +static TCGv_i32 cpu_exclusive_val; +static TCGv_i32 cpu_exclusive_high; +#ifdef CONFIG_USER_ONLY +static TCGv_i32 cpu_exclusive_test; +static TCGv_i32 cpu_exclusive_info; +#endif + +/* FIXME: These should be removed. */ +static TCGv cpu_F0s, cpu_F1s; +static TCGv_i64 cpu_F0d, cpu_F1d; + +#include "gen-icount.h" + +static const char *regnames[] = + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; + +/* initialize TCG globals. */ +void arm_translate_init(void) +{ + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + for (i = 0; i < 16; i++) { + cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, regs[i]), + regnames[i]); + } + cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_addr), "exclusive_addr"); + cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_val), "exclusive_val"); + cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_high), "exclusive_high"); +#ifdef CONFIG_USER_ONLY + cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_test), "exclusive_test"); + cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_info), "exclusive_info"); +#endif + +#define GEN_HELPER 2 +#include "helpers.h" +} + +static int num_temps; + +/* Allocate a temporary variable. */ +static TCGv_i32 new_tmp(void) +{ + num_temps++; + return tcg_temp_new_i32(); +} + +/* Release a temporary variable. */ +static void dead_tmp(TCGv tmp) +{ + tcg_temp_free(tmp); + num_temps--; +} + +static inline TCGv load_cpu_offset(int offset) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name)) + +static inline void store_cpu_offset(TCGv var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + dead_tmp(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUState, name)) + +/* Set a variable to the value of a CPU register. */ +static void load_reg_var(DisasContext *s, TCGv var, int reg) +{ + if (reg == 15) { + uint32_t addr; + /* normaly, since we updated PC, we need only to add one insn */ + if (s->thumb) + addr = (long)s->pc + 2; + else + addr = (long)s->pc + 4; + tcg_gen_movi_i32(var, addr); + } else { + tcg_gen_mov_i32(var, cpu_R[reg]); + } +} + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv load_reg(DisasContext *s, int reg) +{ + TCGv tmp = new_tmp(); + load_reg_var(s, tmp, reg); + return tmp; +} + +/* Set a CPU register. The source must be a temporary and will be + marked as dead. */ +static void store_reg(DisasContext *s, int reg, TCGv var) +{ + if (reg == 15) { + tcg_gen_andi_i32(var, var, ~1); + s->is_jmp = DISAS_JUMP; + } + tcg_gen_mov_i32(cpu_R[reg], var); + dead_tmp(var); +} + +/* Value extensions. */ +#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) +#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) +#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) +#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) + +#define gen_sxtb16(var) gen_helper_sxtb16(var, var) +#define gen_uxtb16(var) gen_helper_uxtb16(var, var) + + +static inline void gen_set_cpsr(TCGv var, uint32_t mask) +{ + TCGv tmp_mask = tcg_const_i32(mask); + gen_helper_cpsr_write(var, tmp_mask); + tcg_temp_free_i32(tmp_mask); +} +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) + +static void gen_exception(int excp) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); + gen_helper_exception(tmp); + dead_tmp(tmp); +} + +static void gen_smul_dual(TCGv a, TCGv b) +{ + TCGv tmp1 = new_tmp(); + TCGv tmp2 = new_tmp(); + tcg_gen_ext16s_i32(tmp1, a); + tcg_gen_ext16s_i32(tmp2, b); + tcg_gen_mul_i32(tmp1, tmp1, tmp2); + dead_tmp(tmp2); + tcg_gen_sari_i32(a, a, 16); + tcg_gen_sari_i32(b, b, 16); + tcg_gen_mul_i32(b, b, a); + tcg_gen_mov_i32(a, tmp1); + dead_tmp(tmp1); +} + +/* Byteswap each halfword. */ +static void gen_rev16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_andi_i32(var, var, 0xff00ff00); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Byteswap low halfword and sign extend. */ +static void gen_revsh(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_ext8s_i32(var, var); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Unsigned bitfield extract. */ +static void gen_ubfx(TCGv var, int shift, uint32_t mask) +{ + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_andi_i32(var, var, mask); +} + +/* Signed bitfield extract. */ +static void gen_sbfx(TCGv var, int shift, int width) +{ + uint32_t signbit; + + if (shift) + tcg_gen_sari_i32(var, var, shift); + if (shift + width < 32) { + signbit = 1u << (width - 1); + tcg_gen_andi_i32(var, var, (1u << width) - 1); + tcg_gen_xori_i32(var, var, signbit); + tcg_gen_subi_i32(var, var, signbit); + } +} + +/* Bitfield insertion. Insert val into base. Clobbers base and val. */ +static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) +{ + tcg_gen_andi_i32(val, val, mask); + tcg_gen_shli_i32(val, val, shift); + tcg_gen_andi_i32(base, base, ~(mask << shift)); + tcg_gen_or_i32(dest, base, val); +} + +/* Round the top 32 bits of a 64-bit value. */ +static void gen_roundqd(TCGv a, TCGv b) +{ + tcg_gen_shri_i32(a, a, 31); + tcg_gen_add_i32(a, a, b); +} + +/* FIXME: Most targets have native widening multiplication. + It would be good to use that instead of a full wide multiply. */ +/* 32x32->64 multiply. Marks inputs as dead. */ +static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_extu_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_ext_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +/* Signed 32x32->64 multiply. */ +static void gen_imull(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + tcg_gen_ext_i32_i64(tmp2, b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + tcg_gen_trunc_i64_i32(a, tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(b, tmp1); + tcg_temp_free_i64(tmp1); +} + +/* Swap low and high halfwords. */ +static void gen_swap_half(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_shli_i32(var, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. + tmp = (t0 ^ t1) & 0x8000; + t0 &= ~0x8000; + t1 &= ~0x8000; + t0 = (t0 + t1) ^ tmp; + */ + +static void gen_add16(TCGv t0, TCGv t1) +{ + TCGv tmp = new_tmp(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andi_i32(tmp, tmp, 0x8000); + tcg_gen_andi_i32(t0, t0, ~0x8000); + tcg_gen_andi_i32(t1, t1, ~0x8000); + tcg_gen_add_i32(t0, t0, t1); + tcg_gen_xor_i32(t0, t0, tmp); + dead_tmp(tmp); + dead_tmp(t1); +} + +#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF)) + +/* Set CF to the top bit of var. */ +static void gen_set_CF_bit31(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 31); + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Set N and Z flags from var. */ +static inline void gen_logic_CC(TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF)); + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF)); +} + +/* T0 += T1 + CF. */ +static void gen_adc(TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(t0, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(t0, t0, tmp); + dead_tmp(tmp); +} + +/* dest = T0 + T1 + CF. */ +static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + dead_tmp(tmp); +} + +/* dest = T0 - T1 + CF - 1. */ +static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_subi_i32(dest, dest, 1); + dead_tmp(tmp); +} + +/* FIXME: Implement this natively. */ +#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) + +static void shifter_out_im(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift == 0) { + tcg_gen_andi_i32(tmp, var, 1); + } else { + tcg_gen_shri_i32(tmp, var, shift); + if (shift != 31) + tcg_gen_andi_i32(tmp, tmp, 1); + } + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Shift by immediate. Includes special handling for shift == 0. */ +static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) +{ + switch (shiftop) { + case 0: /* LSL */ + if (shift != 0) { + if (flags) + shifter_out_im(var, 32 - shift); + tcg_gen_shli_i32(var, var, shift); + } + break; + case 1: /* LSR */ + if (shift == 0) { + if (flags) { + tcg_gen_shri_i32(var, var, 31); + gen_set_CF(var); + } + tcg_gen_movi_i32(var, 0); + } else { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_shri_i32(var, var, shift); + } + break; + case 2: /* ASR */ + if (shift == 0) + shift = 32; + if (flags) + shifter_out_im(var, shift - 1); + if (shift == 32) + shift = 31; + tcg_gen_sari_i32(var, var, shift); + break; + case 3: /* ROR/RRX */ + if (shift != 0) { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_rotri_i32(var, var, shift); break; + } else { + TCGv tmp = load_cpu_field(CF); + if (flags) + shifter_out_im(var, 0); + tcg_gen_shri_i32(var, var, 1); + tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); + } + } +}; + +static inline void gen_arm_shift_reg(TCGv var, int shiftop, + TCGv shift, int flags) +{ + if (flags) { + switch (shiftop) { + case 0: gen_helper_shl_cc(var, var, shift); break; + case 1: gen_helper_shr_cc(var, var, shift); break; + case 2: gen_helper_sar_cc(var, var, shift); break; + case 3: gen_helper_ror_cc(var, var, shift); break; + } + } else { + switch (shiftop) { + case 0: gen_helper_shl(var, var, shift); break; + case 1: gen_helper_shr(var, var, shift); break; + case 2: gen_helper_sar(var, var, shift); break; + case 3: tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_rotr_i32(var, var, shift); break; + } + } + dead_tmp(shift); +} + +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add16)); break; \ + case 1: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 2: gen_pas_helper(glue(pfx,subaddx)); break; \ + case 3: gen_pas_helper(glue(pfx,sub16)); break; \ + case 4: gen_pas_helper(glue(pfx,add8)); break; \ + case 7: gen_pas_helper(glue(pfx,sub8)); break; \ + } +static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv_ptr tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 1: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + tcg_temp_free_ptr(tmp); + break; + case 5: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + tcg_temp_free_ptr(tmp); + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 2: + PAS_OP(q); + break; + case 3: + PAS_OP(sh); + break; + case 6: + PAS_OP(uq); + break; + case 7: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} +#undef PAS_OP + +/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */ +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add8)); break; \ + case 1: gen_pas_helper(glue(pfx,add16)); break; \ + case 2: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 4: gen_pas_helper(glue(pfx,sub8)); break; \ + case 5: gen_pas_helper(glue(pfx,sub16)); break; \ + case 6: gen_pas_helper(glue(pfx,subaddx)); break; \ + } +static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv_ptr tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 0: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + tcg_temp_free_ptr(tmp); + break; + case 4: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + tcg_temp_free_ptr(tmp); + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 1: + PAS_OP(q); + break; + case 2: + PAS_OP(sh); + break; + case 5: + PAS_OP(uq); + break; + case 6: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} +#undef PAS_OP + +static void gen_test_cc(int cc, int label) +{ + TCGv tmp; + TCGv tmp2; + int inv; + + switch (cc) { + case 0: /* eq: Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 1: /* ne: !Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 2: /* cs: C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 3: /* cc: !C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 4: /* mi: N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 5: /* pl: !N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 6: /* vs: V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 7: /* vc: !V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 8: /* hi: C && !Z */ + inv = gen_new_label(); + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + gen_set_label(inv); + break; + case 9: /* ls: !C || Z */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 10: /* ge: N == V -> N ^ V == 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 11: /* lt: N != V -> N ^ V != 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 12: /* gt: !Z && N == V */ + inv = gen_new_label(); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + gen_set_label(inv); + break; + case 13: /* le: Z || N != V */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + default: + fprintf(stderr, "Bad condition code 0x%x\n", cc); + abort(); + } + dead_tmp(tmp); +} + +static const uint8_t table_logic_cc[16] = { + 1, /* and */ + 1, /* xor */ + 0, /* sub */ + 0, /* rsb */ + 0, /* add */ + 0, /* adc */ + 0, /* sbc */ + 0, /* rsc */ + 1, /* andl */ + 1, /* xorl */ + 0, /* cmp */ + 0, /* cmn */ + 1, /* orr */ + 1, /* mov */ + 1, /* bic */ + 1, /* mvn */ +}; + +/* Set PC and Thumb state from an immediate address. */ +static inline void gen_bx_im(DisasContext *s, uint32_t addr) +{ + TCGv tmp; + + s->is_jmp = DISAS_UPDATE; + if (s->thumb != (addr & 1)) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, addr & 1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb)); + dead_tmp(tmp); + } + tcg_gen_movi_i32(cpu_R[15], addr & ~1); +} + +/* Set PC and Thumb state from var. var is marked as dead. */ +static inline void gen_bx(DisasContext *s, TCGv var) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_andi_i32(cpu_R[15], var, ~1); + tcg_gen_andi_i32(var, var, 1); + store_cpu_field(var, thumb); +} + +/* Variant of store_reg which uses branch&exchange logic when storing + to r15 in ARM architecture v7 and above. The source must be a temporary + and will be marked as dead. */ +static inline void store_reg_bx(CPUState *env, DisasContext *s, + int reg, TCGv var) +{ + if (reg == 15 && ENABLE_ARCH_7) { + gen_bx(s, var); + } else { + store_reg(s, reg, var); + } +} + +static inline TCGv gen_ld8s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld8u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld32(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, index); + return tmp; +} +static inline TCGv_i64 gen_ld64(TCGv addr, int index) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp, addr, index); + return tmp; +} +static inline void gen_st8(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st8(val, addr, index); + dead_tmp(val); +} +static inline void gen_st16(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st16(val, addr, index); + dead_tmp(val); +} +static inline void gen_st32(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st32(val, addr, index); + dead_tmp(val); +} +static inline void gen_st64(TCGv_i64 val, TCGv addr, int index) +{ + tcg_gen_qemu_st64(val, addr, index); + tcg_temp_free_i64(val); +} + +static inline void gen_set_pc_im(uint32_t val) +{ + tcg_gen_movi_i32(cpu_R[15], val); +} + +/* Force a TB lookup after an instruction that changes the CPU state. */ +static inline void gen_lookup_tb(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_R[15], s->pc & ~1); + s->is_jmp = DISAS_UPDATE; +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val, rm, shift, shiftop; + TCGv offset; + + if (!(insn & (1 << 25))) { + /* immediate */ + val = insn & 0xfff; + if (!(insn & (1 << 23))) + val = -val; + if (val != 0) + tcg_gen_addi_i32(var, var, val); + } else { + /* shift/register */ + rm = (insn) & 0xf; + shift = (insn >> 7) & 0x1f; + shiftop = (insn >> 5) & 3; + offset = load_reg(s, rm); + gen_arm_shift_im(offset, shiftop, shift, 0); + if (!(insn & (1 << 23))) + tcg_gen_sub_i32(var, var, offset); + else + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, + int extra, TCGv var) +{ + int val, rm; + TCGv offset; + + if (insn & (1 << 22)) { + /* immediate */ + val = (insn & 0xf) | ((insn >> 4) & 0xf0); + if (!(insn & (1 << 23))) + val = -val; + val += extra; + if (val != 0) + tcg_gen_addi_i32(var, var, val); + } else { + /* register */ + if (extra) + tcg_gen_addi_i32(var, var, extra); + rm = (insn) & 0xf; + offset = load_reg(s, rm); + if (!(insn & (1 << 23))) + tcg_gen_sub_i32(var, var, offset); + else + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); + } +} + +#define VFP_OP2(name) \ +static inline void gen_vfp_##name(int dp) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \ +} + +VFP_OP2(add) +VFP_OP2(sub) +VFP_OP2(mul) +VFP_OP2(div) + +#undef VFP_OP2 + +static inline void gen_vfp_abs(int dp) +{ + if (dp) + gen_helper_vfp_absd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_abss(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_neg(int dp) +{ + if (dp) + gen_helper_vfp_negd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_negs(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_sqrt(int dp) +{ + if (dp) + gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env); + else + gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_cmp(int dp) +{ + if (dp) + gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_cmpe(int dp) +{ + if (dp) + gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_F1_ld0(int dp) +{ + if (dp) + tcg_gen_movi_i64(cpu_F1d, 0); + else + tcg_gen_movi_i32(cpu_F1s, 0); +} + +static inline void gen_vfp_uito(int dp) +{ + if (dp) + gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_sito(int dp) +{ + if (dp) + gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_toui(int dp) +{ + if (dp) + gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_touiz(int dp) +{ + if (dp) + gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosi(int dp) +{ + if (dp) + gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosiz(int dp) +{ + if (dp) + gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env); +} + +#define VFP_GEN_FIX(name) \ +static inline void gen_vfp_##name(int dp, int shift) \ +{ \ + TCGv tmp_shift = tcg_const_i32(shift); \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, cpu_env);\ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, cpu_env);\ + tcg_temp_free_i32(tmp_shift); \ +} +VFP_GEN_FIX(tosh) +VFP_GEN_FIX(tosl) +VFP_GEN_FIX(touh) +VFP_GEN_FIX(toul) +VFP_GEN_FIX(shto) +VFP_GEN_FIX(slto) +VFP_GEN_FIX(uhto) +VFP_GEN_FIX(ulto) +#undef VFP_GEN_FIX + +static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr) +{ + if (dp) + tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s)); + else + tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s)); +} + +static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr) +{ + if (dp) + tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s)); + else + tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s)); +} + +static inline long +vfp_reg_offset (int dp, int reg) +{ + if (dp) + return offsetof(CPUARMState, vfp.regs[reg]); + else if (reg & 1) { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} + +/* Return the offset of a 32-bit piece of a NEON register. + zero is the least significant end of the register. */ +static inline long +neon_reg_offset (int reg, int n) +{ + int sreg; + sreg = reg * 2 + n; + return vfp_reg_offset(0, sreg); +} + +static TCGv neon_load_reg(int reg, int pass) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass)); + return tmp; +} + +static void neon_store_reg(int reg, int pass, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); + dead_tmp(var); +} + +static inline void neon_load_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +static inline void neon_store_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +#define tcg_gen_ld_f32 tcg_gen_ld_i32 +#define tcg_gen_ld_f64 tcg_gen_ld_i64 +#define tcg_gen_st_f32 tcg_gen_st_i32 +#define tcg_gen_st_f64 tcg_gen_st_i64 + +static inline void gen_mov_F0_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_F1_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_vreg_F0(int dp, int reg) +{ + if (dp) + tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +#define ARM_CP_RW_BIT (1 << 20) + +static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline void iwmmxt_store_reg(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline TCGv iwmmxt_load_creg(int reg) +{ + TCGv var = new_tmp(); + tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); + return var; +} + +static inline void iwmmxt_store_creg(int reg, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); +} + +static inline void gen_op_iwmmxt_movq_wRn_M0(int rn) +{ + iwmmxt_store_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_movq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_orq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_andq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1); +} + +#define IWMMXT_OP(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV_SIZE(name) \ +IWMMXT_OP_ENV(name##b) \ +IWMMXT_OP_ENV(name##w) \ +IWMMXT_OP_ENV(name##l) + +#define IWMMXT_OP_ENV1(name) \ +static inline void gen_op_iwmmxt_##name##_M0(void) \ +{ \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \ +} + +IWMMXT_OP(maddsq) +IWMMXT_OP(madduq) +IWMMXT_OP(sadb) +IWMMXT_OP(sadw) +IWMMXT_OP(mulslw) +IWMMXT_OP(mulshw) +IWMMXT_OP(mululw) +IWMMXT_OP(muluhw) +IWMMXT_OP(macsw) +IWMMXT_OP(macuw) + +IWMMXT_OP_ENV_SIZE(unpackl) +IWMMXT_OP_ENV_SIZE(unpackh) + +IWMMXT_OP_ENV1(unpacklub) +IWMMXT_OP_ENV1(unpackluw) +IWMMXT_OP_ENV1(unpacklul) +IWMMXT_OP_ENV1(unpackhub) +IWMMXT_OP_ENV1(unpackhuw) +IWMMXT_OP_ENV1(unpackhul) +IWMMXT_OP_ENV1(unpacklsb) +IWMMXT_OP_ENV1(unpacklsw) +IWMMXT_OP_ENV1(unpacklsl) +IWMMXT_OP_ENV1(unpackhsb) +IWMMXT_OP_ENV1(unpackhsw) +IWMMXT_OP_ENV1(unpackhsl) + +IWMMXT_OP_ENV_SIZE(cmpeq) +IWMMXT_OP_ENV_SIZE(cmpgtu) +IWMMXT_OP_ENV_SIZE(cmpgts) + +IWMMXT_OP_ENV_SIZE(mins) +IWMMXT_OP_ENV_SIZE(minu) +IWMMXT_OP_ENV_SIZE(maxs) +IWMMXT_OP_ENV_SIZE(maxu) + +IWMMXT_OP_ENV_SIZE(subn) +IWMMXT_OP_ENV_SIZE(addn) +IWMMXT_OP_ENV_SIZE(subu) +IWMMXT_OP_ENV_SIZE(addu) +IWMMXT_OP_ENV_SIZE(subs) +IWMMXT_OP_ENV_SIZE(adds) + +IWMMXT_OP_ENV(avgb0) +IWMMXT_OP_ENV(avgb1) +IWMMXT_OP_ENV(avgw0) +IWMMXT_OP_ENV(avgw1) + +IWMMXT_OP(msadb) + +IWMMXT_OP_ENV(packuw) +IWMMXT_OP_ENV(packul) +IWMMXT_OP_ENV(packuq) +IWMMXT_OP_ENV(packsw) +IWMMXT_OP_ENV(packsl) +IWMMXT_OP_ENV(packsq) + +static void gen_op_iwmmxt_set_mup(void) +{ + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 2); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); +} + +static void gen_op_iwmmxt_set_cup(void) +{ + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 1); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); +} + +static void gen_op_iwmmxt_setpsr_nz(void) +{ + TCGv tmp = new_tmp(); + gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]); +} + +static inline void gen_op_iwmmxt_addl_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_ext32u_i64(cpu_V1, cpu_V1); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest) +{ + int rd; + uint32_t offset; + TCGv tmp; + + rd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + + offset = (insn & 0xff) << ((insn >> 7) & 2); + if (insn & (1 << 24)) { + /* Pre indexed */ + if (insn & (1 << 23)) + tcg_gen_addi_i32(tmp, tmp, offset); + else + tcg_gen_addi_i32(tmp, tmp, -offset); + tcg_gen_mov_i32(dest, tmp); + if (insn & (1 << 21)) + store_reg(s, rd, tmp); + else + dead_tmp(tmp); + } else if (insn & (1 << 21)) { + /* Post indexed */ + tcg_gen_mov_i32(dest, tmp); + if (insn & (1 << 23)) + tcg_gen_addi_i32(tmp, tmp, offset); + else + tcg_gen_addi_i32(tmp, tmp, -offset); + store_reg(s, rd, tmp); + } else if (!(insn & (1 << 23))) + return 1; + return 0; +} + +static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest) +{ + int rd = (insn >> 0) & 0xf; + TCGv tmp; + + if (insn & (1 << 8)) { + if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) { + return 1; + } else { + tmp = iwmmxt_load_creg(rd); + } + } else { + tmp = new_tmp(); + iwmmxt_load_reg(cpu_V0, rd); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + } + tcg_gen_andi_i32(tmp, tmp, mask); + tcg_gen_mov_i32(dest, tmp); + dead_tmp(tmp); + return 0; +} + +/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int rd, wrd; + int rdhi, rdlo, rd0, rd1, i; + TCGv addr; + TCGv tmp, tmp2, tmp3; + + if ((insn & 0x0e000e00) == 0x0c000000) { + if ((insn & 0x0fe00ff0) == 0x0c400000) { + wrd = insn & 0xf; + rdlo = (insn >> 12) & 0xf; + rdhi = (insn >> 16) & 0xf; + if (insn & ARM_CP_RW_BIT) { /* TMRRC */ + iwmmxt_load_reg(cpu_V0, wrd); + tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0); + } else { /* TMCRR */ + tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]); + iwmmxt_store_reg(cpu_V0, wrd); + gen_op_iwmmxt_set_mup(); + } + return 0; + } + + wrd = (insn >> 12) & 0xf; + addr = new_tmp(); + if (gen_iwmmxt_address(s, insn, addr)) { + dead_tmp(addr); + return 1; + } + if (insn & ARM_CP_RW_BIT) { + if ((insn >> 28) == 0xf) { /* WLDRW wCx */ + tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s)); + iwmmxt_store_creg(wrd, tmp); + } else { + i = 1; + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WLDRD */ + tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s)); + i = 0; + } else { /* WLDRW wRd */ + tmp = gen_ld32(addr, IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WLDRH */ + tmp = gen_ld16u(addr, IS_USER(s)); + } else { /* WLDRB */ + tmp = gen_ld8u(addr, IS_USER(s)); + } + } + if (i) { + tcg_gen_extu_i32_i64(cpu_M0, tmp); + dead_tmp(tmp); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + } + } else { + if ((insn >> 28) == 0xf) { /* WSTRW wCx */ + tmp = iwmmxt_load_creg(wrd); + gen_st32(tmp, addr, IS_USER(s)); + } else { + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = new_tmp(); + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WSTRD */ + dead_tmp(tmp); + tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s)); + } else { /* WSTRW wRd */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st32(tmp, addr, IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WSTRH */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st16(tmp, addr, IS_USER(s)); + } else { /* WSTRB */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st8(tmp, addr, IS_USER(s)); + } + } + } + } + return 0; + } + + if ((insn & 0x0f000000) != 0x0e000000) + return 1; + + switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) { + case 0x000: /* WOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_orq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x011: /* TMCR */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + switch (wrd) { + case ARM_IWMMXT_wCID: + case ARM_IWMMXT_wCASF: + break; + case ARM_IWMMXT_wCon: + gen_op_iwmmxt_set_cup(); + /* Fall through. */ + case ARM_IWMMXT_wCSSF: + tmp = iwmmxt_load_creg(wrd); + tmp2 = load_reg(s, rd); + tcg_gen_andc_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + iwmmxt_store_creg(wrd, tmp); + break; + case ARM_IWMMXT_wCGR0: + case ARM_IWMMXT_wCGR1: + case ARM_IWMMXT_wCGR2: + case ARM_IWMMXT_wCGR3: + gen_op_iwmmxt_set_cup(); + tmp = load_reg(s, rd); + iwmmxt_store_creg(wrd, tmp); + break; + default: + return 1; + } + break; + case 0x100: /* WXOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_xorq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x111: /* TMRC */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = iwmmxt_load_creg(wrd); + store_reg(s, rd, tmp); + break; + case 0x300: /* WANDN */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tcg_gen_neg_i64(cpu_M0, cpu_M0); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x200: /* WAND */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x810: case 0xa10: /* WMADD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_maddsq_M0_wRn(rd1); + else + gen_op_iwmmxt_madduq_M0_wRn(rd1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpacklb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpacklw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackll_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpackhb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpackhw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackhl_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) + gen_op_iwmmxt_sadw_M0_wRn(rd1); + else + gen_op_iwmmxt_sadb_M0_wRn(rd1); + if (!(insn & (1 << 20))) + gen_op_iwmmxt_addl_M0_wRn(wrd); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_mulshw_M0_wRn(rd1); + else + gen_op_iwmmxt_mulslw_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_muluhw_M0_wRn(rd1); + else + gen_op_iwmmxt_mululw_M0_wRn(rd1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_macsw_M0_wRn(rd1); + else + gen_op_iwmmxt_macuw_M0_wRn(rd1); + if (!(insn & (1 << 20))) { + iwmmxt_load_reg(cpu_V1, wrd); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_cmpeqb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_cmpeqw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_cmpeql_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgw1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgw0_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgb1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgb0_M0_wRn(rd1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3)); + tcg_gen_andi_i32(tmp, tmp, 7); + iwmmxt_load_reg(cpu_V1, rd1); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */ + if (((insn >> 6) & 3) == 3) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + gen_op_iwmmxt_movq_M0_wRn(wrd); + switch ((insn >> 6) & 3) { + case 0: + tmp2 = tcg_const_i32(0xff); + tmp3 = tcg_const_i32((insn & 7) << 3); + break; + case 1: + tmp2 = tcg_const_i32(0xffff); + tmp3 = tcg_const_i32((insn & 3) << 4); + break; + case 2: + tmp2 = tcg_const_i32(0xffffffff); + tmp3 = tcg_const_i32((insn & 1) << 5); + break; + default: + TCGV_UNUSED(tmp2); + TCGV_UNUSED(tmp3); + } + gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3); + tcg_temp_free(tmp3); + tcg_temp_free(tmp2); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */ + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + if (rd == 15 || ((insn >> 22) & 3) == 3) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 0: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + if (insn & 8) { + tcg_gen_ext8s_i32(tmp, tmp); + } else { + tcg_gen_andi_i32(tmp, tmp, 0xff); + } + break; + case 1: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + if (insn & 8) { + tcg_gen_ext16s_i32(tmp, tmp); + } else { + tcg_gen_andi_i32(tmp, tmp, 0xffff); + } + break; + case 2: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + break; + } + store_reg(s, rd, tmp); + break; + case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */ + if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + switch ((insn >> 22) & 3) { + case 0: + tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0); + break; + case 1: + tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4); + break; + case 2: + tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12); + break; + } + tcg_gen_shli_i32(tmp, tmp, 28); + gen_set_nzcv(tmp); + dead_tmp(tmp); + break; + case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */ + if (((insn >> 6) & 3) == 3) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + switch ((insn >> 6) & 3) { + case 0: + gen_helper_iwmmxt_bcstb(cpu_M0, tmp); + break; + case 1: + gen_helper_iwmmxt_bcstw(cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_bcstl(cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */ + if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 4); + tcg_gen_and_i32(tmp, tmp, tmp2); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 8); + tcg_gen_and_i32(tmp, tmp, tmp2); + } + break; + case 2: + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_and_i32(tmp, tmp, tmp2); + break; + } + gen_set_nzcv(tmp); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0); + break; + case 1: + gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0); + break; + case 2: + gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */ + if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 4); + tcg_gen_or_i32(tmp, tmp, tmp2); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 8); + tcg_gen_or_i32(tmp, tmp, tmp2); + } + break; + case 2: + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp, tmp, tmp2); + break; + } + gen_set_nzcv(tmp); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */ + rd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3) + return 1; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 0: + gen_helper_iwmmxt_msbb(tmp, cpu_M0); + break; + case 1: + gen_helper_iwmmxt_msbw(tmp, cpu_M0); + break; + case 2: + gen_helper_iwmmxt_msbl(tmp, cpu_M0); + break; + } + store_reg(s, rd, tmp); + break; + case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */ + case 0x906: case 0xb06: case 0xd06: case 0xf06: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */ + case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsb_M0(); + else + gen_op_iwmmxt_unpacklub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsw_M0(); + else + gen_op_iwmmxt_unpackluw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsl_M0(); + else + gen_op_iwmmxt_unpacklul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */ + case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsb_M0(); + else + gen_op_iwmmxt_unpackhub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsw_M0(); + else + gen_op_iwmmxt_unpackhuw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsl_M0(); + else + gen_op_iwmmxt_unpackhul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */ + case 0x214: case 0x614: case 0xa14: case 0xe14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */ + case 0x014: case 0x414: case 0x814: case 0xc14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */ + case 0x114: case 0x514: case 0x914: case 0xd14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */ + case 0x314: case 0x714: case 0xb14: case 0xf14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 1: + if (gen_iwmmxt_shift(insn, 0xf, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + if (gen_iwmmxt_shift(insn, 0x1f, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + if (gen_iwmmxt_shift(insn, 0x3f, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */ + case 0x916: case 0xb16: case 0xd16: case 0xf16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsb_M0_wRn(rd1); + else + gen_op_iwmmxt_minub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsw_M0_wRn(rd1); + else + gen_op_iwmmxt_minuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsl_M0_wRn(rd1); + else + gen_op_iwmmxt_minul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */ + case 0x816: case 0xa16: case 0xc16: case 0xe16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsb_M0_wRn(rd1); + else + gen_op_iwmmxt_maxub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsw_M0_wRn(rd1); + else + gen_op_iwmmxt_maxuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsl_M0_wRn(rd1); + else + gen_op_iwmmxt_maxul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */ + case 0x402: case 0x502: case 0x602: case 0x702: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = tcg_const_i32((insn >> 20) & 3); + iwmmxt_load_reg(cpu_V1, rd1); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp); + tcg_temp_free(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */ + case 0x41a: case 0x51a: case 0x61a: case 0x71a: + case 0x81a: case 0x91a: case 0xa1a: case 0xb1a: + case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_subnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_subub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_subsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_subnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_subuw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_subsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_subnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_subul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_subsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */ + case 0x41e: case 0x51e: case 0x61e: case 0x71e: + case 0x81e: case 0x91e: case 0xa1e: case 0xb1e: + case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); + gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp); + tcg_temp_free(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */ + case 0x418: case 0x518: case 0x618: case 0x718: + case 0x818: case 0x918: case 0xa18: case 0xb18: + case 0xc18: case 0xd18: case 0xe18: case 0xf18: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_addnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_addub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_addsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_addnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_adduw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_addsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_addnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_addul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_addsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */ + case 0x408: case 0x508: case 0x608: case 0x708: + case 0x808: case 0x908: case 0xa08: case 0xb08: + case 0xc08: case 0xd08: case 0xe08: case 0xf08: + if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsw_M0_wRn(rd1); + else + gen_op_iwmmxt_packuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsl_M0_wRn(rd1); + else + gen_op_iwmmxt_packul_M0_wRn(rd1); + break; + case 3: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsq_M0_wRn(rd1); + else + gen_op_iwmmxt_packuq_M0_wRn(rd1); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x201: case 0x203: case 0x205: case 0x207: + case 0x209: case 0x20b: case 0x20d: case 0x20f: + case 0x211: case 0x213: case 0x215: case 0x217: + case 0x219: case 0x21b: case 0x21d: case 0x21f: + wrd = (insn >> 5) & 0xf; + rd0 = (insn >> 12) & 0xf; + rd1 = (insn >> 0) & 0xf; + if (rd0 == 0xf || rd1 == 0xf) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = load_reg(s, rd0); + tmp2 = load_reg(s, rd1); + switch ((insn >> 16) & 0xf) { + case 0x0: /* TMIA */ + gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0x8: /* TMIAPH */ + gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */ + if (insn & (1 << 16)) + tcg_gen_shri_i32(tmp, tmp, 16); + if (insn & (1 << 17)) + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2); + break; + default: + dead_tmp(tmp2); + dead_tmp(tmp); + return 1; + } + dead_tmp(tmp2); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + default: + return 1; + } + + return 0; +} + +/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int acc, rd0, rd1, rdhi, rdlo; + TCGv tmp, tmp2; + + if ((insn & 0x0ff00f10) == 0x0e200010) { + /* Multiply with Internal Accumulate Format */ + rd0 = (insn >> 12) & 0xf; + rd1 = insn & 0xf; + acc = (insn >> 5) & 7; + + if (acc != 0) + return 1; + + tmp = load_reg(s, rd0); + tmp2 = load_reg(s, rd1); + switch ((insn >> 16) & 0xf) { + case 0x0: /* MIA */ + gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0x8: /* MIAPH */ + gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0xc: /* MIABB */ + case 0xd: /* MIABT */ + case 0xe: /* MIATB */ + case 0xf: /* MIATT */ + if (insn & (1 << 16)) + tcg_gen_shri_i32(tmp, tmp, 16); + if (insn & (1 << 17)) + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2); + break; + default: + return 1; + } + dead_tmp(tmp2); + dead_tmp(tmp); + + gen_op_iwmmxt_movq_wRn_M0(acc); + return 0; + } + + if ((insn & 0x0fe00ff8) == 0x0c400000) { + /* Internal Accumulator Access Format */ + rdhi = (insn >> 16) & 0xf; + rdlo = (insn >> 12) & 0xf; + acc = insn & 7; + + if (acc != 0) + return 1; + + if (insn & ARM_CP_RW_BIT) { /* MRA */ + iwmmxt_load_reg(cpu_V0, acc); + tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0); + tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1); + } else { /* MAR */ + tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]); + iwmmxt_store_reg(cpu_V0, acc); + } + return 0; + } + + return 1; +} + +/* Disassemble system coprocessor instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp, tmp2; + uint32_t rd = (insn >> 12) & 0xf; + uint32_t cp = (insn >> 8) & 0xf; + if (IS_USER(s)) { + return 1; + } + + if (insn & ARM_CP_RW_BIT) { + if (!env->cp[cp].cp_read) + return 1; + gen_set_pc_im(s->pc); + tmp = new_tmp(); + tmp2 = tcg_const_i32(insn); + gen_helper_get_cp(tmp, cpu_env, tmp2); + tcg_temp_free(tmp2); + store_reg(s, rd, tmp); + } else { + if (!env->cp[cp].cp_write) + return 1; + gen_set_pc_im(s->pc); + tmp = load_reg(s, rd); + tmp2 = tcg_const_i32(insn); + gen_helper_set_cp(cpu_env, tmp2, tmp); + tcg_temp_free(tmp2); + dead_tmp(tmp); + } + return 0; +} + +static int cp15_user_ok(uint32_t insn) +{ + int cpn = (insn >> 16) & 0xf; + int cpm = insn & 0xf; + int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); + + if (cpn == 13 && cpm == 0) { + /* TLS register. */ + if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) + return 1; + } + if (cpn == 7) { + /* ISB, DSB, DMB. */ + if ((cpm == 5 && op == 4) + || (cpm == 10 && (op == 4 || op == 5))) + return 1; + } + return 0; +} + +/* Disassemble system coprocessor (cp15) instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + uint32_t rd; + TCGv tmp, tmp2; + + /* M profile cores use memory mapped registers instead of cp15. */ + if (arm_feature(env, ARM_FEATURE_M)) + return 1; + + if ((insn & (1 << 25)) == 0) { + if (insn & (1 << 20)) { + /* mrrc */ + return 1; + } + /* mcrr. Used for block cache operations, so implement as no-op. */ + return 0; + } + if ((insn & (1 << 4)) == 0) { + /* cdp */ + return 1; + } + if (IS_USER(s) && !cp15_user_ok(insn)) { + return 1; + } + if ((insn & 0x0fff0fff) == 0x0e070f90 + || (insn & 0x0fff0fff) == 0x0e070f58) { + /* Wait for interrupt. */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_WFI; + return 0; + } + rd = (insn >> 12) & 0xf; + tmp2 = tcg_const_i32(insn); + if (insn & ARM_CP_RW_BIT) { + tmp = new_tmp(); + gen_helper_get_cp15(tmp, cpu_env, tmp2); + /* If the destination register is r15 then sets condition codes. */ + if (rd != 15) + store_reg(s, rd, tmp); + else + dead_tmp(tmp); + } else { + tmp = load_reg(s, rd); + gen_helper_set_cp15(cpu_env, tmp2, tmp); + dead_tmp(tmp); + /* Normally we would always end the TB here, but Linux + * arch/arm/mach-pxa/sleep.S expects two instructions following + * an MMU enable to execute from cache. Imitate this behaviour. */ + if (!arm_feature(env, ARM_FEATURE_XSCALE) || + (insn & 0x0fff0fff) != 0x0e010f10) + gen_lookup_tb(s); + } + tcg_temp_free_i32(tmp2); + return 0; +} + +#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) +#define VFP_SREG(insn, bigbit, smallbit) \ + ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) +#define VFP_DREG(reg, insn, bigbit, smallbit) do { \ + if (arm_feature(env, ARM_FEATURE_VFP3)) { \ + reg = (((insn) >> (bigbit)) & 0x0f) \ + | (((insn) >> ((smallbit) - 4)) & 0x10); \ + } else { \ + if (insn & (1 << (smallbit))) \ + return 1; \ + reg = ((insn) >> (bigbit)) & 0x0f; \ + }} while (0) + +#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22) +#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22) +#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7) +#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) +#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) +#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) + +/* Move between integer and VFP cores. */ +static TCGv gen_vfp_mrs(void) +{ + TCGv tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_F0s); + return tmp; +} + +static void gen_vfp_msr(TCGv tmp) +{ + tcg_gen_mov_i32(cpu_F0s, tmp); + dead_tmp(tmp); +} + +static inline int +vfp_enabled(CPUState * env) +{ + return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0); +} + +static void gen_neon_dup_u8(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_ext8u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 8); + tcg_gen_or_i32(var, var, tmp); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_low16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_ext16u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_high16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_andi_i32(var, var, 0xffff0000); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Disassemble a VFP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; + int dp, veclen; + TCGv addr; + TCGv tmp; + TCGv tmp2; + + if (!arm_feature(env, ARM_FEATURE_VFP)) + return 1; + + if (!vfp_enabled(env)) { + /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */ + if ((insn & 0x0fe00fff) != 0x0ee00a10) + return 1; + rn = (insn >> 16) & 0xf; + if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC + && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) + return 1; + } + dp = ((insn & 0xf00) == 0xb00); + switch ((insn >> 24) & 0xf) { + case 0xe: + if (insn & (1 << 4)) { + /* single register transfer */ + rd = (insn >> 12) & 0xf; + if (dp) { + int size; + int pass; + + VFP_DREG_N(rn, insn); + if (insn & 0xf) + return 1; + if (insn & 0x00c00060 + && !arm_feature(env, ARM_FEATURE_NEON)) + return 1; + + pass = (insn >> 21) & 1; + if (insn & (1 << 22)) { + size = 0; + offset = ((insn >> 5) & 3) * 8; + } else if (insn & (1 << 5)) { + size = 1; + offset = (insn & (1 << 6)) ? 16 : 0; + } else { + size = 2; + offset = 0; + } + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + tmp = neon_load_reg(rn, pass); + switch (size) { + case 0: + if (offset) + tcg_gen_shri_i32(tmp, tmp, offset); + if (insn & (1 << 23)) + gen_uxtb(tmp); + else + gen_sxtb(tmp); + break; + case 1: + if (insn & (1 << 23)) { + if (offset) { + tcg_gen_shri_i32(tmp, tmp, 16); + } else { + gen_uxth(tmp); + } + } else { + if (offset) { + tcg_gen_sari_i32(tmp, tmp, 16); + } else { + gen_sxth(tmp); + } + } + break; + case 2: + break; + } + store_reg(s, rd, tmp); + } else { + /* arm->vfp */ + tmp = load_reg(s, rd); + if (insn & (1 << 23)) { + /* VDUP */ + if (size == 0) { + gen_neon_dup_u8(tmp, 0); + } else if (size == 1) { + gen_neon_dup_low16(tmp); + } + for (n = 0; n <= pass * 2; n++) { + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rn, n, tmp2); + } + neon_store_reg(rn, n, tmp); + } else { + /* VMOV */ + switch (size) { + case 0: + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xff); + dead_tmp(tmp2); + break; + case 1: + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xffff); + dead_tmp(tmp2); + break; + case 2: + break; + } + neon_store_reg(rn, pass, tmp); + } + } + } else { /* !dp */ + if ((insn & 0x6f) != 0x00) + return 1; + rn = VFP_SREG_N(insn); + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + if (insn & (1 << 21)) { + /* system register */ + rn >>= 1; + + switch (rn) { + case ARM_VFP_FPSID: + /* VFP2 allows access to FSID from userspace. + VFP3 restricts all id registers to privileged + accesses. */ + if (IS_USER(s) + && arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + /* Not present in VFP3. */ + if (IS_USER(s) + || arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPSCR: + if (rd == 15) { + tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); + tcg_gen_andi_i32(tmp, tmp, 0xf0000000); + } else { + tmp = new_tmp(); + gen_helper_vfp_get_fpscr(tmp, cpu_env); + } + break; + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: + if (IS_USER(s) + || !arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + default: + return 1; + } + } else { + gen_mov_F0_vreg(0, rn); + tmp = gen_vfp_mrs(); + } + if (rd == 15) { + /* Set the 4 flag bits in the CPSR. */ + gen_set_nzcv(tmp); + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + } + } else { + /* arm->vfp */ + tmp = load_reg(s, rd); + if (insn & (1 << 21)) { + rn >>= 1; + /* system register */ + switch (rn) { + case ARM_VFP_FPSID: + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: + /* Writes are ignored. */ + break; + case ARM_VFP_FPSCR: + gen_helper_vfp_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); + gen_lookup_tb(s); + break; + case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; + /* TODO: VFP subarchitecture support. + * For now, keep the EN bit only */ + tcg_gen_andi_i32(tmp, tmp, 1 << 30); + store_cpu_field(tmp, vfp.xregs[rn]); + gen_lookup_tb(s); + break; + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + store_cpu_field(tmp, vfp.xregs[rn]); + break; + default: + return 1; + } + } else { + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rn); + } + } + } + } else { + /* data processing */ + /* The opcode is in bits 23, 21, 20 and 6. */ + op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1); + if (dp) { + if (op == 15) { + /* rn is opcode */ + rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + } else { + /* rn is register number */ + VFP_DREG_N(rn, insn); + } + + if (op == 15 && (rn == 15 || rn > 17)) { + /* Integer or single precision destination. */ + rd = VFP_SREG_D(insn); + } else { + VFP_DREG_D(rd, insn); + } + + if (op == 15 && (rn == 16 || rn == 17)) { + /* Integer source. */ + rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + } else { + VFP_DREG_M(rm, insn); + } + } else { + rn = VFP_SREG_N(insn); + if (op == 15 && rn == 15) { + /* Double precision destination. */ + VFP_DREG_D(rd, insn); + } else { + rd = VFP_SREG_D(insn); + } + rm = VFP_SREG_M(insn); + } + + veclen = env->vfp.vec_len; + if (op == 15 && rn > 3) + veclen = 0; + + /* Shut up compiler warnings. */ + delta_m = 0; + delta_d = 0; + bank_mask = 0; + + if (veclen > 0) { + if (dp) + bank_mask = 0xc; + else + bank_mask = 0x18; + + /* Figure out what type of vector operation this is. */ + if ((rd & bank_mask) == 0) { + /* scalar */ + veclen = 0; + } else { + if (dp) + delta_d = (env->vfp.vec_stride >> 1) + 1; + else + delta_d = env->vfp.vec_stride + 1; + + if ((rm & bank_mask) == 0) { + /* mixed scalar/vector */ + delta_m = 0; + } else { + /* vector */ + delta_m = delta_d; + } + } + } + + /* Load the initial operands. */ + if (op == 15) { + switch (rn) { + case 16: + case 17: + /* Integer source */ + gen_mov_F0_vreg(0, rm); + break; + case 8: + case 9: + /* Compare */ + gen_mov_F0_vreg(dp, rd); + gen_mov_F1_vreg(dp, rm); + break; + case 10: + case 11: + /* Compare with zero */ + gen_mov_F0_vreg(dp, rd); + gen_vfp_F1_ld0(dp); + break; + case 20: + case 21: + case 22: + case 23: + case 28: + case 29: + case 30: + case 31: + /* Source and destination the same. */ + gen_mov_F0_vreg(dp, rd); + break; + default: + /* One source operand. */ + gen_mov_F0_vreg(dp, rm); + break; + } + } else { + /* Two source operands. */ + gen_mov_F0_vreg(dp, rn); + gen_mov_F1_vreg(dp, rm); + } + + for (;;) { + /* Perform the calculation. */ + switch (op) { + case 0: /* mac: fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 1: /* nmac: fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 2: /* msc: -fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); + break; + case 3: /* nmsc: -fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); + break; + case 4: /* mul: fn * fm */ + gen_vfp_mul(dp); + break; + case 5: /* nmul: -(fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + break; + case 6: /* add: fn + fm */ + gen_vfp_add(dp); + break; + case 7: /* sub: fn - fm */ + gen_vfp_sub(dp); + break; + case 8: /* div: fn / fm */ + gen_vfp_div(dp); + break; + case 14: /* fconst */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + + n = (insn << 12) & 0x80000000; + i = ((insn >> 12) & 0x70) | (insn & 0xf); + if (dp) { + if (i & 0x40) + i |= 0x3f80; + else + i |= 0x4000; + n |= i << 16; + tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32); + } else { + if (i & 0x40) + i |= 0x780; + else + i |= 0x800; + n |= i << 19; + tcg_gen_movi_i32(cpu_F0s, n); + } + break; + case 15: /* extension space */ + switch (rn) { + case 0: /* cpy */ + /* no-op */ + break; + case 1: /* abs */ + gen_vfp_abs(dp); + break; + case 2: /* neg */ + gen_vfp_neg(dp); + break; + case 3: /* sqrt */ + gen_vfp_sqrt(dp); + break; + case 4: /* vcvtb.f32.f16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = gen_vfp_mrs(); + tcg_gen_ext16u_i32(tmp, tmp); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); + dead_tmp(tmp); + break; + case 5: /* vcvtt.f32.f16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = gen_vfp_mrs(); + tcg_gen_shri_i32(tmp, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); + dead_tmp(tmp); + break; + case 6: /* vcvtb.f16.f32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + gen_mov_F0_vreg(0, rd); + tmp2 = gen_vfp_mrs(); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + gen_vfp_msr(tmp); + break; + case 7: /* vcvtt.f16.f32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp, tmp, 16); + gen_mov_F0_vreg(0, rd); + tmp2 = gen_vfp_mrs(); + tcg_gen_ext16u_i32(tmp2, tmp2); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + gen_vfp_msr(tmp); + break; + case 8: /* cmp */ + gen_vfp_cmp(dp); + break; + case 9: /* cmpe */ + gen_vfp_cmpe(dp); + break; + case 10: /* cmpz */ + gen_vfp_cmp(dp); + break; + case 11: /* cmpez */ + gen_vfp_F1_ld0(dp); + gen_vfp_cmpe(dp); + break; + case 15: /* single<->double conversion */ + if (dp) + gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); + break; + case 16: /* fuito */ + gen_vfp_uito(dp); + break; + case 17: /* fsito */ + gen_vfp_sito(dp); + break; + case 20: /* fshto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_shto(dp, 16 - rm); + break; + case 21: /* fslto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_slto(dp, 32 - rm); + break; + case 22: /* fuhto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_uhto(dp, 16 - rm); + break; + case 23: /* fulto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_ulto(dp, 32 - rm); + break; + case 24: /* ftoui */ + gen_vfp_toui(dp); + break; + case 25: /* ftouiz */ + gen_vfp_touiz(dp); + break; + case 26: /* ftosi */ + gen_vfp_tosi(dp); + break; + case 27: /* ftosiz */ + gen_vfp_tosiz(dp); + break; + case 28: /* ftosh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosh(dp, 16 - rm); + break; + case 29: /* ftosl */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosl(dp, 32 - rm); + break; + case 30: /* ftouh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_touh(dp, 16 - rm); + break; + case 31: /* ftoul */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_toul(dp, 32 - rm); + break; + default: /* undefined */ + printf ("rn:%d\n", rn); + return 1; + } + break; + default: /* undefined */ + printf ("op:%d\n", op); + return 1; + } + + /* Write back the result. */ + if (op == 15 && (rn >= 8 && rn <= 11)) + ; /* Comparison, do nothing. */ + else if (op == 15 && rn > 17) + /* Integer result. */ + gen_mov_vreg_F0(0, rd); + else if (op == 15 && rn == 15) + /* conversion */ + gen_mov_vreg_F0(!dp, rd); + else + gen_mov_vreg_F0(dp, rd); + + /* break out of the loop if we have finished */ + if (veclen == 0) + break; + + if (op == 15 && delta_m == 0) { + /* single source one-many */ + while (veclen--) { + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + gen_mov_vreg_F0(dp, rd); + } + break; + } + /* Setup the next operands. */ + veclen--; + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + + if (op == 15) { + /* One source operand. */ + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F0_vreg(dp, rm); + } else { + /* Two source operands. */ + rn = ((rn + delta_d) & (bank_mask - 1)) + | (rn & bank_mask); + gen_mov_F0_vreg(dp, rn); + if (delta_m) { + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F1_vreg(dp, rm); + } + } + } + } + break; + case 0xc: + case 0xd: + if (dp && (insn & 0x03e00000) == 0x00400000) { + /* two-register transfer */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (dp) { + VFP_DREG_M(rm, insn); + } else { + rm = VFP_SREG_M(insn); + } + + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + if (dp) { + gen_mov_F0_vreg(0, rm * 2); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + gen_mov_F0_vreg(0, rm * 2 + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); + } else { + gen_mov_F0_vreg(0, rm); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); + gen_mov_F0_vreg(0, rm + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + } + } else { + /* arm->vfp */ + if (dp) { + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2 + 1); + } else { + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm + 1); + } + } + } else { + /* Load/store */ + rn = (insn >> 16) & 0xf; + if (dp) + VFP_DREG_D(rd, insn); + else + rd = VFP_SREG_D(insn); + if (s->thumb && rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } + if ((insn & 0x01200000) == 0x01000000) { + /* Single load/store */ + offset = (insn & 0xff) << 2; + if ((insn & (1 << 23)) == 0) + offset = -offset; + tcg_gen_addi_i32(addr, addr, offset); + if (insn & (1 << 20)) { + gen_vfp_ld(s, dp, addr); + gen_mov_vreg_F0(dp, rd); + } else { + gen_mov_F0_vreg(dp, rd); + gen_vfp_st(s, dp, addr); + } + dead_tmp(addr); + } else { + /* load/store multiple */ + if (dp) + n = (insn >> 1) & 0x7f; + else + n = insn & 0xff; + + if (insn & (1 << 24)) /* pre-decrement */ + tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2)); + + if (dp) + offset = 8; + else + offset = 4; + for (i = 0; i < n; i++) { + if (insn & ARM_CP_RW_BIT) { + /* load */ + gen_vfp_ld(s, dp, addr); + gen_mov_vreg_F0(dp, rd + i); + } else { + /* store */ + gen_mov_F0_vreg(dp, rd + i); + gen_vfp_st(s, dp, addr); + } + tcg_gen_addi_i32(addr, addr, offset); + } + if (insn & (1 << 21)) { + /* writeback */ + if (insn & (1 << 24)) + offset = -offset * n; + else if (dp && (insn & 1)) + offset = 4; + else + offset = 0; + + if (offset != 0) + tcg_gen_addi_i32(addr, addr, offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + } + break; + default: + /* Should never happen. */ + return 1; + } + return 0; +} + +static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + gen_set_pc_im(dest); + tcg_gen_exit_tb((long)tb + n); + } else { + gen_set_pc_im(dest); + tcg_gen_exit_tb(0); + } +} + +static inline void gen_jmp (DisasContext *s, uint32_t dest) +{ + if (unlikely(s->singlestep_enabled)) { + /* An indirect jump so that we still trigger the debug exception. */ + if (s->thumb) + dest |= 1; + gen_bx_im(s, dest); + } else { + gen_goto_tb(s, 0, dest); + s->is_jmp = DISAS_TB_JUMP; + } +} + +static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y) +{ + if (x) + tcg_gen_sari_i32(t0, t0, 16); + else + gen_sxth(t0); + if (y) + tcg_gen_sari_i32(t1, t1, 16); + else + gen_sxth(t1); + tcg_gen_mul_i32(t0, t0, t1); +} + +/* Return the mask of PSR bits set by a MSR instruction. */ +static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { + uint32_t mask; + + mask = 0; + if (flags & (1 << 0)) + mask |= 0xff; + if (flags & (1 << 1)) + mask |= 0xff00; + if (flags & (1 << 2)) + mask |= 0xff0000; + if (flags & (1 << 3)) + mask |= 0xff000000; + + /* Mask out undefined bits. */ + mask &= ~CPSR_RESERVED; + if (!arm_feature(env, ARM_FEATURE_V6)) + mask &= ~(CPSR_E | CPSR_GE); + if (!arm_feature(env, ARM_FEATURE_THUMB2)) + mask &= ~CPSR_IT; + /* Mask out execution state bits. */ + if (!spsr) + mask &= ~CPSR_EXEC; + /* Mask out privileged bits. */ + if (IS_USER(s)) + mask &= CPSR_USER; + return mask; +} + +/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ +static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0) +{ + TCGv tmp; + if (spsr) { + /* ??? This is also undefined in system mode. */ + if (IS_USER(s)) + return 1; + + tmp = load_cpu_field(spsr); + tcg_gen_andi_i32(tmp, tmp, ~mask); + tcg_gen_andi_i32(t0, t0, mask); + tcg_gen_or_i32(tmp, tmp, t0); + store_cpu_field(tmp, spsr); + } else { + gen_set_cpsr(t0, mask); + } + dead_tmp(t0); + gen_lookup_tb(s); + return 0; +} + +/* Returns nonzero if access to the PSR is not permitted. */ +static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + return gen_set_psr(s, mask, spsr, tmp); +} + +/* Generate an old-style exception return. Marks pc as dead. */ +static void gen_exception_return(DisasContext *s, TCGv pc) +{ + TCGv tmp; + store_reg(s, 15, pc); + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; +} + +/* Generate a v6 exception return. Marks both values as dead. */ +static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr) +{ + gen_set_cpsr(cpsr, 0xffffffff); + dead_tmp(cpsr); + store_reg(s, 15, pc); + s->is_jmp = DISAS_UPDATE; +} + +static inline void +gen_set_condexec (DisasContext *s) +{ + if (s->condexec_mask) { + uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_cpu_field(tmp, condexec_bits); + } +} + +static void gen_nop_hint(DisasContext *s, int val) +{ + switch (val) { + case 3: /* wfi */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_WFI; + break; + case 2: /* wfe */ + case 4: /* sev */ + /* TODO: Implement SEV and WFE. May help SMP performance. */ + default: /* nop */ + break; + } +} + +#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 + +static inline int gen_neon_add(int size, TCGv t0, TCGv t1) +{ + switch (size) { + case 0: gen_helper_neon_add_u8(t0, t0, t1); break; + case 1: gen_helper_neon_add_u16(t0, t0, t1); break; + case 2: tcg_gen_add_i32(t0, t0, t1); break; + default: return 1; + } + return 0; +} + +static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1) +{ + switch (size) { + case 0: gen_helper_neon_sub_u8(t0, t1, t0); break; + case 1: gen_helper_neon_sub_u16(t0, t1, t0); break; + case 2: tcg_gen_sub_i32(t0, t1, t0); break; + default: return; + } +} + +/* 32-bit pairwise ops end up the same as the elementwise versions. */ +#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32 +#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32 +#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32 +#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32 + +/* FIXME: This is wrong. They set the wrong overflow bit. */ +#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c) +#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c) +#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c) +#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c) + +#define GEN_NEON_INTEGER_OP_ENV(name) do { \ + switch ((size << 1) | u) { \ + case 0: \ + gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \ + break; \ + default: return 1; \ + }} while (0) + +#define GEN_NEON_INTEGER_OP(name) do { \ + switch ((size << 1) | u) { \ + case 0: \ + gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \ + break; \ + default: return 1; \ + }} while (0) + +static TCGv neon_load_scratch(int scratch) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); + return tmp; +} + +static void neon_store_scratch(int scratch, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); + dead_tmp(var); +} + +static inline TCGv neon_get_scalar(int size, int reg) +{ + TCGv tmp; + if (size == 1) { + tmp = neon_load_reg(reg >> 1, reg & 1); + } else { + tmp = neon_load_reg(reg >> 2, (reg >> 1) & 1); + if (reg & 1) { + gen_neon_dup_low16(tmp); + } else { + gen_neon_dup_high16(tmp); + } + } + return tmp; +} + +static void gen_neon_unzip_u8(TCGv t0, TCGv t1) +{ + TCGv rd, rm, tmp; + + rd = new_tmp(); + rm = new_tmp(); + tmp = new_tmp(); + + tcg_gen_andi_i32(rd, t0, 0xff); + tcg_gen_shri_i32(tmp, t0, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff000000); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(rm, t0, 8); + tcg_gen_andi_i32(rm, rm, 0xff); + tcg_gen_shri_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_andi_i32(tmp, t1, 0xff000000); + tcg_gen_or_i32(t1, rm, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rm); + dead_tmp(rd); +} + +static void gen_neon_zip_u8(TCGv t0, TCGv t1) +{ + TCGv rd, rm, tmp; + + rd = new_tmp(); + rm = new_tmp(); + tmp = new_tmp(); + + tcg_gen_andi_i32(rd, t0, 0xff); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 24); + tcg_gen_andi_i32(tmp, tmp, 0xff000000); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_andi_i32(rm, t1, 0xff000000); + tcg_gen_shri_i32(tmp, t0, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shri_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shri_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff); + tcg_gen_or_i32(t1, rm, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rm); + dead_tmp(rd); +} + +static void gen_neon_zip_u16(TCGv t0, TCGv t1) +{ + TCGv tmp, tmp2; + + tmp = new_tmp(); + tmp2 = new_tmp(); + + tcg_gen_andi_i32(tmp, t0, 0xffff); + tcg_gen_shli_i32(tmp2, t1, 16); + tcg_gen_or_i32(tmp, tmp, tmp2); + tcg_gen_andi_i32(t1, t1, 0xffff0000); + tcg_gen_shri_i32(tmp2, t0, 16); + tcg_gen_or_i32(t1, t1, tmp2); + tcg_gen_mov_i32(t0, tmp); + + dead_tmp(tmp2); + dead_tmp(tmp); +} + +static void gen_neon_unzip(int reg, int q, int tmp, int size) +{ + int n; + TCGv t0, t1; + + for (n = 0; n < q + 1; n += 2) { + t0 = neon_load_reg(reg, n); + t1 = neon_load_reg(reg, n + 1); + switch (size) { + case 0: gen_neon_unzip_u8(t0, t1); break; + case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same. */ + case 2: /* no-op */; break; + default: abort(); + } + neon_store_scratch(tmp + n, t0); + neon_store_scratch(tmp + n + 1, t1); + } +} + +static void gen_neon_trn_u8(TCGv t0, TCGv t1) +{ + TCGv rd, tmp; + + rd = new_tmp(); + tmp = new_tmp(); + + tcg_gen_shli_i32(rd, t0, 8); + tcg_gen_andi_i32(rd, rd, 0xff00ff00); + tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(t1, t1, 8); + tcg_gen_andi_i32(t1, t1, 0x00ff00ff); + tcg_gen_andi_i32(tmp, t0, 0xff00ff00); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rd); +} + +static void gen_neon_trn_u16(TCGv t0, TCGv t1) +{ + TCGv rd, tmp; + + rd = new_tmp(); + tmp = new_tmp(); + + tcg_gen_shli_i32(rd, t0, 16); + tcg_gen_andi_i32(tmp, t1, 0xffff); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shri_i32(t1, t1, 16); + tcg_gen_andi_i32(tmp, t0, 0xffff0000); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rd); +} + + +static struct { + int nregs; + int interleave; + int spacing; +} neon_ls_element_type[11] = { + {4, 4, 1}, + {4, 4, 2}, + {4, 1, 1}, + {4, 2, 1}, + {3, 3, 1}, + {3, 3, 2}, + {3, 1, 1}, + {1, 1, 1}, + {2, 2, 1}, + {2, 2, 2}, + {2, 1, 1} +}; + +/* Translate a NEON load/store element instruction. Return nonzero if the + instruction is invalid. */ +static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int rd, rn, rm; + int op; + int nregs; + int interleave; + int spacing; + int stride; + int size; + int reg; + int pass; + int load; + int shift; + int n; + TCGv addr; + TCGv tmp; + TCGv tmp2; + TCGv_i64 tmp64; + + if (!vfp_enabled(env)) + return 1; + VFP_DREG_D(rd, insn); + rn = (insn >> 16) & 0xf; + rm = insn & 0xf; + load = (insn & (1 << 21)) != 0; + addr = new_tmp(); + if ((insn & (1 << 23)) == 0) { + /* Load store all elements. */ + op = (insn >> 8) & 0xf; + size = (insn >> 6) & 3; + if (op > 10) + return 1; + nregs = neon_ls_element_type[op].nregs; + interleave = neon_ls_element_type[op].interleave; + spacing = neon_ls_element_type[op].spacing; + if (size == 3 && (interleave | spacing) != 1) + return 1; + load_reg_var(s, addr, rn); + stride = (1 << size) * interleave; + for (reg = 0; reg < nregs; reg++) { + if (interleave > 2 || (interleave == 2 && nregs == 2)) { + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, (1 << size) * reg); + } else if (interleave == 2 && nregs == 4 && reg == 2) { + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, 1 << size); + } + if (size == 3) { + if (load) { + tmp64 = gen_ld64(addr, IS_USER(s)); + neon_store_reg64(tmp64, rd); + tcg_temp_free_i64(tmp64); + } else { + tmp64 = tcg_temp_new_i64(); + neon_load_reg64(tmp64, rd); + gen_st64(tmp64, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, stride); + } else { + for (pass = 0; pass < 2; pass++) { + if (size == 2) { + if (load) { + tmp = gen_ld32(addr, IS_USER(s)); + neon_store_reg(rd, pass, tmp); + } else { + tmp = neon_load_reg(rd, pass); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, stride); + } else if (size == 1) { + if (load) { + tmp = gen_ld16u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + tmp2 = gen_ld16u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + gen_bfi(tmp, tmp, tmp2, 16, 0xffff); + dead_tmp(tmp2); + neon_store_reg(rd, pass, tmp); + } else { + tmp = neon_load_reg(rd, pass); + tmp2 = new_tmp(); + tcg_gen_shri_i32(tmp2, tmp, 16); + gen_st16(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + gen_st16(tmp2, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + } + } else /* size == 0 */ { + if (load) { + TCGV_UNUSED(tmp2); + for (n = 0; n < 4; n++) { + tmp = gen_ld8u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + if (n == 0) { + tmp2 = tmp; + } else { + gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff); + dead_tmp(tmp); + } + } + neon_store_reg(rd, pass, tmp2); + } else { + tmp2 = neon_load_reg(rd, pass); + for (n = 0; n < 4; n++) { + tmp = new_tmp(); + if (n == 0) { + tcg_gen_mov_i32(tmp, tmp2); + } else { + tcg_gen_shri_i32(tmp, tmp2, n * 8); + } + gen_st8(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + } + dead_tmp(tmp2); + } + } + } + } + rd += spacing; + } + stride = nregs * 8; + } else { + size = (insn >> 10) & 3; + if (size == 3) { + /* Load single element to all lanes. */ + if (!load) + return 1; + size = (insn >> 6) & 3; + nregs = ((insn >> 8) & 3) + 1; + stride = (insn & (1 << 5)) ? 2 : 1; + load_reg_var(s, addr, rn); + for (reg = 0; reg < nregs; reg++) { + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + gen_neon_dup_u8(tmp, 0); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + gen_neon_dup_low16(tmp); + break; + case 2: + tmp = gen_ld32(addr, IS_USER(s)); + break; + case 3: + return 1; + default: /* Avoid compiler warnings. */ + abort(); + } + tcg_gen_addi_i32(addr, addr, 1 << size); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); + rd += stride; + } + stride = (1 << size) * nregs; + } else { + /* Single element. */ + pass = (insn >> 7) & 1; + switch (size) { + case 0: + shift = ((insn >> 5) & 3) * 8; + stride = 1; + break; + case 1: + shift = ((insn >> 6) & 1) * 16; + stride = (insn & (1 << 5)) ? 2 : 1; + break; + case 2: + shift = 0; + stride = (insn & (1 << 6)) ? 2 : 1; + break; + default: + abort(); + } + nregs = ((insn >> 8) & 3) + 1; + load_reg_var(s, addr, rn); + for (reg = 0; reg < nregs; reg++) { + if (load) { + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: /* Avoid compiler warnings. */ + abort(); + } + if (size != 2) { + tmp2 = neon_load_reg(rd, pass); + gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff); + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } else { /* Store */ + tmp = neon_load_reg(rd, pass); + if (shift) + tcg_gen_shri_i32(tmp, tmp, shift); + switch (size) { + case 0: + gen_st8(tmp, addr, IS_USER(s)); + break; + case 1: + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: + gen_st32(tmp, addr, IS_USER(s)); + break; + } + } + rd += stride; + tcg_gen_addi_i32(addr, addr, 1 << size); + } + stride = nregs * (1 << size); + } + } + dead_tmp(addr); + if (rm != 15) { + TCGv base; + + base = load_reg(s, rn); + if (rm == 13) { + tcg_gen_addi_i32(base, base, stride); + } else { + TCGv index; + index = load_reg(s, rm); + tcg_gen_add_i32(base, base, index); + dead_tmp(index); + } + store_reg(s, rn, base); + } + return 0; +} + +/* Bitwise select. dest = c ? t : f. Clobbers T and F. */ +static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c) +{ + tcg_gen_and_i32(t, t, c); + tcg_gen_andc_i32(f, f, c); + tcg_gen_or_i32(dest, t, f); +} + +static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_u8(dest, src); break; + case 1: gen_helper_neon_narrow_u16(dest, src); break; + case 2: tcg_gen_trunc_i64_i32(dest, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift, + int q, int u) +{ + if (q) { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_rshl_s16(var, var, shift); break; + case 2: gen_helper_neon_rshl_s32(var, var, shift); break; + default: abort(); + } + } + } else { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_shl_s16(var, var, shift); break; + case 2: gen_helper_neon_shl_s32(var, var, shift); break; + default: abort(); + } + } + } +} + +static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u) +{ + if (u) { + switch (size) { + case 0: gen_helper_neon_widen_u8(dest, src); break; + case 1: gen_helper_neon_widen_u16(dest, src); break; + case 2: tcg_gen_extu_i32_i64(dest, src); break; + default: abort(); + } + } else { + switch (size) { + case 0: gen_helper_neon_widen_s8(dest, src); break; + case 1: gen_helper_neon_widen_s16(dest, src); break; + case 2: tcg_gen_ext_i32_i64(dest, src); break; + default: abort(); + } + } + dead_tmp(src); +} + +static inline void gen_neon_addl(int size) +{ + switch (size) { + case 0: gen_helper_neon_addl_u16(CPU_V001); break; + case 1: gen_helper_neon_addl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_subl(int size) +{ + switch (size) { + case 0: gen_helper_neon_subl_u16(CPU_V001); break; + case 1: gen_helper_neon_subl_u32(CPU_V001); break; + case 2: tcg_gen_sub_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_negl(TCGv_i64 var, int size) +{ + switch (size) { + case 0: gen_helper_neon_negl_u16(var, var); break; + case 1: gen_helper_neon_negl_u32(var, var); break; + case 2: gen_helper_neon_negl_u64(var, var); break; + default: abort(); + } +} + +static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size) +{ + switch (size) { + case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break; + case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break; + default: abort(); + } +} + +static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u) +{ + TCGv_i64 tmp; + + switch ((size << 1) | u) { + case 0: gen_helper_neon_mull_s8(dest, a, b); break; + case 1: gen_helper_neon_mull_u8(dest, a, b); break; + case 2: gen_helper_neon_mull_s16(dest, a, b); break; + case 3: gen_helper_neon_mull_u16(dest, a, b); break; + case 4: + tmp = gen_muls_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + case 5: + tmp = gen_mulu_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + default: abort(); + } +} + +/* Translate a NEON data processing instruction. Return nonzero if the + instruction is invalid. + We process data in a mixture of 32-bit and 64-bit chunks. + Mostly we use 32-bit chunks so we can use normal scalar instructions. */ + +static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int op; + int q; + int rd, rn, rm; + int size; + int shift; + int pass; + int count; + int pairwise; + int u; + int n; + uint32_t imm, mask; + TCGv tmp, tmp2, tmp3, tmp4, tmp5; + TCGv_i64 tmp64; + + if (!vfp_enabled(env)) + return 1; + q = (insn & (1 << 6)) != 0; + u = (insn >> 24) & 1; + VFP_DREG_D(rd, insn); + VFP_DREG_N(rn, insn); + VFP_DREG_M(rm, insn); + size = (insn >> 20) & 3; + if ((insn & (1 << 23)) == 0) { + /* Three register same length. */ + op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); + if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9 + || op == 10 || op == 11 || op == 16)) { + /* 64-bit element instructions. */ + for (pass = 0; pass < (q ? 2 : 1); pass++) { + neon_load_reg64(cpu_V0, rn + pass); + neon_load_reg64(cpu_V1, rm + pass); + switch (op) { + case 1: /* VQADD */ + if (u) { + gen_helper_neon_add_saturate_u64(CPU_V001); + } else { + gen_helper_neon_add_saturate_s64(CPU_V001); + } + break; + case 5: /* VQSUB */ + if (u) { + gen_helper_neon_sub_saturate_u64(CPU_V001); + } else { + gen_helper_neon_sub_saturate_s64(CPU_V001); + } + break; + case 8: /* VSHL */ + if (u) { + gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 9: /* VQSHL */ + if (u) { + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, + cpu_V0, cpu_V0); + } else { + gen_helper_neon_qshl_s64(cpu_V1, cpu_env, + cpu_V1, cpu_V0); + } + break; + case 10: /* VRSHL */ + if (u) { + gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 11: /* VQRSHL */ + if (u) { + gen_helper_neon_qrshl_u64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); + } else { + gen_helper_neon_qrshl_s64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); + } + break; + case 16: + if (u) { + tcg_gen_sub_i64(CPU_V001); + } else { + tcg_gen_add_i64(CPU_V001); + } + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } + return 0; + } + switch (op) { + case 8: /* VSHL */ + case 9: /* VQSHL */ + case 10: /* VRSHL */ + case 11: /* VQRSHL */ + { + int rtmp; + /* Shift instruction operands are reversed. */ + rtmp = rn; + rn = rm; + rm = rtmp; + pairwise = 0; + } + break; + case 20: /* VPMAX */ + case 21: /* VPMIN */ + case 23: /* VPADD */ + pairwise = 1; + break; + case 26: /* VPADD (float) */ + pairwise = (u && size < 2); + break; + case 30: /* VPMIN/VPMAX (float) */ + pairwise = u; + break; + default: + pairwise = 0; + break; + } + + for (pass = 0; pass < (q ? 4 : 2); pass++) { + + if (pairwise) { + /* Pairwise. */ + if (q) + n = (pass & 1) * 2; + else + n = 0; + if (pass < q + 1) { + tmp = neon_load_reg(rn, n); + tmp2 = neon_load_reg(rn, n + 1); + } else { + tmp = neon_load_reg(rm, n); + tmp2 = neon_load_reg(rm, n + 1); + } + } else { + /* Elementwise. */ + tmp = neon_load_reg(rn, pass); + tmp2 = neon_load_reg(rm, pass); + } + switch (op) { + case 0: /* VHADD */ + GEN_NEON_INTEGER_OP(hadd); + break; + case 1: /* VQADD */ + GEN_NEON_INTEGER_OP_ENV(qadd); + break; + case 2: /* VRHADD */ + GEN_NEON_INTEGER_OP(rhadd); + break; + case 3: /* Logic ops. */ + switch ((u << 2) | size) { + case 0: /* VAND */ + tcg_gen_and_i32(tmp, tmp, tmp2); + break; + case 1: /* BIC */ + tcg_gen_andc_i32(tmp, tmp, tmp2); + break; + case 2: /* VORR */ + tcg_gen_or_i32(tmp, tmp, tmp2); + break; + case 3: /* VORN */ + tcg_gen_orc_i32(tmp, tmp, tmp2); + break; + case 4: /* VEOR */ + tcg_gen_xor_i32(tmp, tmp, tmp2); + break; + case 5: /* VBSL */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp, tmp2, tmp3); + dead_tmp(tmp3); + break; + case 6: /* VBIT */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp, tmp3, tmp2); + dead_tmp(tmp3); + break; + case 7: /* VBIF */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + break; + } + break; + case 4: /* VHSUB */ + GEN_NEON_INTEGER_OP(hsub); + break; + case 5: /* VQSUB */ + GEN_NEON_INTEGER_OP_ENV(qsub); + break; + case 6: /* VCGT */ + GEN_NEON_INTEGER_OP(cgt); + break; + case 7: /* VCGE */ + GEN_NEON_INTEGER_OP(cge); + break; + case 8: /* VSHL */ + GEN_NEON_INTEGER_OP(shl); + break; + case 9: /* VQSHL */ + GEN_NEON_INTEGER_OP_ENV(qshl); + break; + case 10: /* VRSHL */ + GEN_NEON_INTEGER_OP(rshl); + break; + case 11: /* VQRSHL */ + GEN_NEON_INTEGER_OP_ENV(qrshl); + break; + case 12: /* VMAX */ + GEN_NEON_INTEGER_OP(max); + break; + case 13: /* VMIN */ + GEN_NEON_INTEGER_OP(min); + break; + case 14: /* VABD */ + GEN_NEON_INTEGER_OP(abd); + break; + case 15: /* VABA */ + GEN_NEON_INTEGER_OP(abd); + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + gen_neon_add(size, tmp, tmp2); + break; + case 16: + if (!u) { /* VADD */ + if (gen_neon_add(size, tmp, tmp2)) + return 1; + } else { /* VSUB */ + switch (size) { + case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 17: + if (!u) { /* VTST */ + switch (size) { + case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break; + default: return 1; + } + } else { /* VCEQ */ + switch (size) { + case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 18: /* Multiply. */ + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + if (u) { /* VMLS */ + gen_neon_rsb(size, tmp, tmp2); + } else { /* VMLA */ + gen_neon_add(size, tmp, tmp2); + } + break; + case 19: /* VMUL */ + if (u) { /* polynomial */ + gen_helper_neon_mul_p8(tmp, tmp, tmp2); + } else { /* Integer */ + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 20: /* VPMAX */ + GEN_NEON_INTEGER_OP(pmax); + break; + case 21: /* VPMIN */ + GEN_NEON_INTEGER_OP(pmin); + break; + case 22: /* Hultiply high. */ + if (!u) { /* VQDMULH */ + switch (size) { + case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + } else { /* VQRDHMUL */ + switch (size) { + case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + } + break; + case 23: /* VPADD */ + if (u) + return 1; + switch (size) { + case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break; + default: return 1; + } + break; + case 26: /* Floating point arithnetic. */ + switch ((u << 2) | size) { + case 0: /* VADD */ + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 2: /* VSUB */ + gen_helper_neon_sub_f32(tmp, tmp, tmp2); + break; + case 4: /* VPADD */ + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 6: /* VABD */ + gen_helper_neon_abd_f32(tmp, tmp, tmp2); + break; + default: + return 1; + } + break; + case 27: /* Float multiply. */ + gen_helper_neon_mul_f32(tmp, tmp, tmp2); + if (!u) { + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + if (size == 0) { + gen_helper_neon_add_f32(tmp, tmp, tmp2); + } else { + gen_helper_neon_sub_f32(tmp, tmp2, tmp); + } + } + break; + case 28: /* Float compare. */ + if (!u) { + gen_helper_neon_ceq_f32(tmp, tmp, tmp2); + } else { + if (size == 0) + gen_helper_neon_cge_f32(tmp, tmp, tmp2); + else + gen_helper_neon_cgt_f32(tmp, tmp, tmp2); + } + break; + case 29: /* Float compare absolute. */ + if (!u) + return 1; + if (size == 0) + gen_helper_neon_acge_f32(tmp, tmp, tmp2); + else + gen_helper_neon_acgt_f32(tmp, tmp, tmp2); + break; + case 30: /* Float min/max. */ + if (size == 0) + gen_helper_neon_max_f32(tmp, tmp, tmp2); + else + gen_helper_neon_min_f32(tmp, tmp, tmp2); + break; + case 31: + if (size == 0) + gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env); + else + gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env); + break; + default: + abort(); + } + dead_tmp(tmp2); + + /* Save the result. For elementwise operations we can put it + straight into the destination register. For pairwise operations + we have to be careful to avoid clobbering the source operands. */ + if (pairwise && rd == rm) { + neon_store_scratch(pass, tmp); + } else { + neon_store_reg(rd, pass, tmp); + } + + } /* for pass */ + if (pairwise && rd == rm) { + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tmp = neon_load_scratch(pass); + neon_store_reg(rd, pass, tmp); + } + } + /* End of 3 register same size operations. */ + } else if (insn & (1 << 4)) { + if ((insn & 0x00380080) != 0) { + /* Two registers and shift. */ + op = (insn >> 8) & 0xf; + if (insn & (1 << 7)) { + /* 64-bit shift. */ + size = 3; + } else { + size = 2; + while ((insn & (1 << (size + 19))) == 0) + size--; + } + shift = (insn >> 16) & ((1 << (3 + size)) - 1); + /* To avoid excessive dumplication of ops we implement shift + by immediate using the variable shift operations. */ + if (op < 8) { + /* Shift by immediate: + VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ + /* Right shifts are encoded as N - shift, where N is the + element size in bits. */ + if (op <= 4) + shift = shift - (1 << (size + 3)); + if (size == 3) { + count = q + 1; + } else { + count = q ? 4: 2; + } + switch (size) { + case 0: + imm = (uint8_t) shift; + imm |= imm << 8; + imm |= imm << 16; + break; + case 1: + imm = (uint16_t) shift; + imm |= imm << 16; + break; + case 2: + case 3: + imm = shift; + break; + default: + abort(); + } + + for (pass = 0; pass < count; pass++) { + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + tcg_gen_movi_i64(cpu_V1, imm); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + else + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1); + break; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1); + else + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); + break; + case 4: /* VSRI */ + if (!u) + return 1; + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 5: /* VSHL, VSLI */ + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 6: /* VQSHL */ + if (u) + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + else + gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + break; + case 7: /* VQSHLU */ + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + break; + } + if (op == 1 || op == 3) { + /* Accumulate. */ + neon_load_reg64(cpu_V0, rd + pass); + tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + cpu_abort(env, "VS[LR]I.64 not implemented"); + } + neon_store_reg64(cpu_V0, rd + pass); + } else { /* size < 3 */ + /* Operands in T0 and T1. */ + tmp = neon_load_reg(rm, pass); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, imm); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + GEN_NEON_INTEGER_OP(shl); + break; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + GEN_NEON_INTEGER_OP(rshl); + break; + case 4: /* VSRI */ + if (!u) + return 1; + GEN_NEON_INTEGER_OP(shl); + break; + case 5: /* VSHL, VSLI */ + switch (size) { + case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break; + default: return 1; + } + break; + case 6: /* VQSHL */ + GEN_NEON_INTEGER_OP_ENV(qshl); + break; + case 7: /* VQSHLU */ + switch (size) { + case 0: gen_helper_neon_qshl_u8(tmp, cpu_env, tmp, tmp2); break; + case 1: gen_helper_neon_qshl_u16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qshl_u32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + break; + } + dead_tmp(tmp2); + + if (op == 1 || op == 3) { + /* Accumulate. */ + tmp2 = neon_load_reg(rd, pass); + gen_neon_add(size, tmp2, tmp); + dead_tmp(tmp2); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + switch (size) { + case 0: + if (op == 4) + mask = 0xff >> -shift; + else + mask = (uint8_t)(0xff << shift); + mask |= mask << 8; + mask |= mask << 16; + break; + case 1: + if (op == 4) + mask = 0xffff >> -shift; + else + mask = (uint16_t)(0xffff << shift); + mask |= mask << 16; + break; + case 2: + if (shift < -31 || shift > 31) { + mask = 0; + } else { + if (op == 4) + mask = 0xffffffffu >> -shift; + else + mask = 0xffffffffu << shift; + } + break; + default: + abort(); + } + tmp2 = neon_load_reg(rd, pass); + tcg_gen_andi_i32(tmp, tmp, mask); + tcg_gen_andi_i32(tmp2, tmp2, ~mask); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } + } /* for pass */ + } else if (op < 10) { + /* Shift by immediate and narrow: + VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ + shift = shift - (1 << (size + 3)); + size++; + switch (size) { + case 1: + imm = (uint16_t)shift; + imm |= imm << 16; + tmp2 = tcg_const_i32(imm); + TCGV_UNUSED_I64(tmp64); + break; + case 2: + imm = (uint32_t)shift; + tmp2 = tcg_const_i32(imm); + TCGV_UNUSED_I64(tmp64); + break; + case 3: + tmp64 = tcg_const_i64(shift); + TCGV_UNUSED(tmp2); + break; + default: + abort(); + } + + for (pass = 0; pass < 2; pass++) { + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + if (q) { + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64); + else + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64); + } else { + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64); + else + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64); + } + } else { + tmp = neon_load_reg(rm + pass, 0); + gen_neon_shift_narrow(size, tmp, tmp2, q, u); + tmp3 = neon_load_reg(rm + pass, 1); + gen_neon_shift_narrow(size, tmp3, tmp2, q, u); + tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3); + dead_tmp(tmp); + dead_tmp(tmp3); + } + tmp = new_tmp(); + if (op == 8 && !u) { + gen_neon_narrow(size - 1, tmp, cpu_V0); + } else { + if (op == 8) + gen_neon_narrow_sats(size - 1, tmp, cpu_V0); + else + gen_neon_narrow_satu(size - 1, tmp, cpu_V0); + } + neon_store_reg(rd, pass, tmp); + } /* for pass */ + if (size == 3) { + tcg_temp_free_i64(tmp64); + } else { + dead_tmp(tmp2); + } + } else if (op == 10) { + /* VSHLL */ + if (q || size == 3) + return 1; + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + for (pass = 0; pass < 2; pass++) { + if (pass == 1) + tmp = tmp2; + + gen_neon_widen(cpu_V0, tmp, size, u); + + if (shift != 0) { + /* The shift is less than the width of the source + type, so we can just shift the whole register. */ + tcg_gen_shli_i64(cpu_V0, cpu_V0, shift); + if (size < 2 || !u) { + uint64_t imm64; + if (size == 0) { + imm = (0xffu >> (8 - shift)); + imm |= imm << 16; + } else { + imm = 0xffff >> (16 - shift); + } + imm64 = imm | (((uint64_t)imm) << 32); + tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64); + } + } + neon_store_reg64(cpu_V0, rd + pass); + } + } else if (op == 15 || op == 16) { + /* VCVT fixed-point. */ + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); + if (op & 1) { + if (u) + gen_vfp_ulto(0, shift); + else + gen_vfp_slto(0, shift); + } else { + if (u) + gen_vfp_toul(0, shift); + else + gen_vfp_tosl(0, shift); + } + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); + } + } else { + return 1; + } + } else { /* (insn & 0x00380080) == 0 */ + int invert; + + op = (insn >> 8) & 0xf; + /* One register and immediate. */ + imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); + invert = (insn & (1 << 5)) != 0; + switch (op) { + case 0: case 1: + /* no-op */ + break; + case 2: case 3: + imm <<= 8; + break; + case 4: case 5: + imm <<= 16; + break; + case 6: case 7: + imm <<= 24; + break; + case 8: case 9: + imm |= imm << 16; + break; + case 10: case 11: + imm = (imm << 8) | (imm << 24); + break; + case 12: + imm = (imm < 8) | 0xff; + break; + case 13: + imm = (imm << 16) | 0xffff; + break; + case 14: + imm |= (imm << 8) | (imm << 16) | (imm << 24); + if (invert) + imm = ~imm; + break; + case 15: + imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) + | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); + break; + } + if (invert) + imm = ~imm; + + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op & 1 && op < 12) { + tmp = neon_load_reg(rd, pass); + if (invert) { + /* The immediate value has already been inverted, so + BIC becomes AND. */ + tcg_gen_andi_i32(tmp, tmp, imm); + } else { + tcg_gen_ori_i32(tmp, tmp, imm); + } + } else { + /* VMOV, VMVN. */ + tmp = new_tmp(); + if (op == 14 && invert) { + uint32_t val; + val = 0; + for (n = 0; n < 4; n++) { + if (imm & (1 << (n + (pass & 1) * 4))) + val |= 0xff << (n * 8); + } + tcg_gen_movi_i32(tmp, val); + } else { + tcg_gen_movi_i32(tmp, imm); + } + } + neon_store_reg(rd, pass, tmp); + } + } + } else { /* (insn & 0x00800010 == 0x00800000) */ + if (size != 3) { + op = (insn >> 8) & 0xf; + if ((insn & (1 << 6)) == 0) { + /* Three registers of different lengths. */ + int src1_wide; + int src2_wide; + int prewiden; + /* prewiden, src1_wide, src2_wide */ + static const int neon_3reg_wide[16][3] = { + {1, 0, 0}, /* VADDL */ + {1, 1, 0}, /* VADDW */ + {1, 0, 0}, /* VSUBL */ + {1, 1, 0}, /* VSUBW */ + {0, 1, 1}, /* VADDHN */ + {0, 0, 0}, /* VABAL */ + {0, 1, 1}, /* VSUBHN */ + {0, 0, 0}, /* VABDL */ + {0, 0, 0}, /* VMLAL */ + {0, 0, 0}, /* VQDMLAL */ + {0, 0, 0}, /* VMLSL */ + {0, 0, 0}, /* VQDMLSL */ + {0, 0, 0}, /* Integer VMULL */ + {0, 0, 0}, /* VQDMULL */ + {0, 0, 0} /* Polynomial VMULL */ + }; + + prewiden = neon_3reg_wide[op][0]; + src1_wide = neon_3reg_wide[op][1]; + src2_wide = neon_3reg_wide[op][2]; + + if (size == 0 && (op == 9 || op == 11 || op == 13)) + return 1; + + /* Avoid overlapping operands. Wide source operands are + always aligned so will never overlap with wide + destinations in problematic ways. */ + if (rd == rm && !src2_wide) { + tmp = neon_load_reg(rm, 1); + neon_store_scratch(2, tmp); + } else if (rd == rn && !src1_wide) { + tmp = neon_load_reg(rn, 1); + neon_store_scratch(2, tmp); + } + TCGV_UNUSED(tmp3); + for (pass = 0; pass < 2; pass++) { + if (src1_wide) { + neon_load_reg64(cpu_V0, rn + pass); + TCGV_UNUSED(tmp); + } else { + if (pass == 1 && rd == rn) { + tmp = neon_load_scratch(2); + } else { + tmp = neon_load_reg(rn, pass); + } + if (prewiden) { + gen_neon_widen(cpu_V0, tmp, size, u); + } + } + if (src2_wide) { + neon_load_reg64(cpu_V1, rm + pass); + TCGV_UNUSED(tmp2); + } else { + if (pass == 1 && rd == rm) { + tmp2 = neon_load_scratch(2); + } else { + tmp2 = neon_load_reg(rm, pass); + } + if (prewiden) { + gen_neon_widen(cpu_V1, tmp2, size, u); + } + } + switch (op) { + case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ + gen_neon_addl(size); + break; + case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */ + gen_neon_subl(size); + break; + case 5: case 7: /* VABAL, VABDL */ + switch ((size << 1) | u) { + case 0: + gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2); + break; + case 1: + gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2); + break; + case 2: + gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2); + break; + case 3: + gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2); + break; + case 4: + gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2); + break; + case 5: + gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2); + break; + default: abort(); + } + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 8: case 9: case 10: case 11: case 12: case 13: + /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 14: /* Polynomial VMULL */ + cpu_abort(env, "Polynomial VMULL not implemented"); + + default: /* 15 is RESERVED. */ + return 1; + } + if (op == 5 || op == 13 || (op >= 8 && op <= 11)) { + /* Accumulate. */ + if (op == 10 || op == 11) { + gen_neon_negl(cpu_V0, size); + } + + if (op != 13) { + neon_load_reg64(cpu_V1, rd + pass); + } + + switch (op) { + case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */ + gen_neon_addl(size); + break; + case 9: case 11: /* VQDMLAL, VQDMLSL */ + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); + break; + /* Fall through. */ + case 13: /* VQDMULL */ + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } else if (op == 4 || op == 6) { + /* Narrowing operation. */ + tmp = new_tmp(); + if (u) { + switch (size) { + case 0: + gen_helper_neon_narrow_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; + default: abort(); + } + } else { + switch (size) { + case 0: + gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; + default: abort(); + } + } + if (pass == 0) { + tmp3 = tmp; + } else { + neon_store_reg(rd, 0, tmp3); + neon_store_reg(rd, 1, tmp); + } + } else { + /* Write back the result. */ + neon_store_reg64(cpu_V0, rd + pass); + } + } + } else { + /* Two registers and a scalar. */ + switch (op) { + case 0: /* Integer VMLA scalar */ + case 1: /* Float VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 5: /* Floating point VMLS scalar */ + case 8: /* Integer VMUL scalar */ + case 9: /* Floating point VMUL scalar */ + case 12: /* VQDMULH scalar */ + case 13: /* VQRDMULH scalar */ + tmp = neon_get_scalar(size, rm); + neon_store_scratch(0, tmp); + for (pass = 0; pass < (u ? 4 : 2); pass++) { + tmp = neon_load_scratch(0); + tmp2 = neon_load_reg(rn, pass); + if (op == 12) { + if (size == 1) { + gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); + } else { + gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); + } + } else if (op == 13) { + if (size == 1) { + gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); + } else { + gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); + } + } else if (op & 1) { + gen_helper_neon_mul_f32(tmp, tmp, tmp2); + } else { + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + dead_tmp(tmp2); + if (op < 8) { + /* Accumulate. */ + tmp2 = neon_load_reg(rd, pass); + switch (op) { + case 0: + gen_neon_add(size, tmp, tmp2); + break; + case 1: + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 4: + gen_neon_rsb(size, tmp, tmp2); + break; + case 5: + gen_helper_neon_sub_f32(tmp, tmp2, tmp); + break; + default: + abort(); + } + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } + break; + case 2: /* VMLAL sclar */ + case 3: /* VQDMLAL scalar */ + case 6: /* VMLSL scalar */ + case 7: /* VQDMLSL scalar */ + case 10: /* VMULL scalar */ + case 11: /* VQDMULL scalar */ + if (size == 0 && (op == 3 || op == 7 || op == 11)) + return 1; + + tmp2 = neon_get_scalar(size, rm); + tmp3 = neon_load_reg(rn, 1); + + for (pass = 0; pass < 2; pass++) { + if (pass == 0) { + tmp = neon_load_reg(rn, 0); + } else { + tmp = tmp3; + } + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); + dead_tmp(tmp); + if (op == 6 || op == 7) { + gen_neon_negl(cpu_V0, size); + } + if (op != 11) { + neon_load_reg64(cpu_V1, rd + pass); + } + switch (op) { + case 2: case 6: + gen_neon_addl(size); + break; + case 3: case 7: + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); + break; + case 10: + /* no-op */ + break; + case 11: + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } + + dead_tmp(tmp2); + + break; + default: /* 14 and 15 are RESERVED */ + return 1; + } + } + } else { /* size == 3 */ + if (!u) { + /* Extract. */ + imm = (insn >> 8) & 0xf; + count = q + 1; + + if (imm > 7 && !q) + return 1; + + if (imm == 0) { + neon_load_reg64(cpu_V0, rn); + if (q) { + neon_load_reg64(cpu_V1, rn + 1); + } + } else if (imm == 8) { + neon_load_reg64(cpu_V0, rn + 1); + if (q) { + neon_load_reg64(cpu_V1, rm); + } + } else if (q) { + tmp64 = tcg_temp_new_i64(); + if (imm < 8) { + neon_load_reg64(cpu_V0, rn); + neon_load_reg64(tmp64, rn + 1); + } else { + neon_load_reg64(cpu_V0, rn + 1); + neon_load_reg64(tmp64, rm); + } + tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8); + tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + if (imm < 8) { + neon_load_reg64(cpu_V1, rm); + } else { + neon_load_reg64(cpu_V1, rm + 1); + imm -= 8; + } + tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_shri_i64(tmp64, tmp64, imm * 8); + tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* BUGFIX */ + neon_load_reg64(cpu_V0, rn); + tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8); + neon_load_reg64(cpu_V1, rm); + tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + } + neon_store_reg64(cpu_V0, rd); + if (q) { + neon_store_reg64(cpu_V1, rd + 1); + } + } else if ((insn & (1 << 11)) == 0) { + /* Two register misc. */ + op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); + size = (insn >> 18) & 3; + switch (op) { + case 0: /* VREV64 */ + if (size == 3) + return 1; + for (pass = 0; pass < (q ? 2 : 1); pass++) { + tmp = neon_load_reg(rm, pass * 2); + tmp2 = neon_load_reg(rm, pass * 2 + 1); + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_swap_half(tmp); break; + case 2: /* no-op */ break; + default: abort(); + } + neon_store_reg(rd, pass * 2 + 1, tmp); + if (size == 2) { + neon_store_reg(rd, pass * 2, tmp2); + } else { + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break; + case 1: gen_swap_half(tmp2); break; + default: abort(); + } + neon_store_reg(rd, pass * 2, tmp2); + } + } + break; + case 4: case 5: /* VPADDL */ + case 12: case 13: /* VPADAL */ + if (size == 3) + return 1; + for (pass = 0; pass < q + 1; pass++) { + tmp = neon_load_reg(rm, pass * 2); + gen_neon_widen(cpu_V0, tmp, size, op & 1); + tmp = neon_load_reg(rm, pass * 2 + 1); + gen_neon_widen(cpu_V1, tmp, size, op & 1); + switch (size) { + case 0: gen_helper_neon_paddl_u16(CPU_V001); break; + case 1: gen_helper_neon_paddl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } + if (op >= 12) { + /* Accumulate. */ + neon_load_reg64(cpu_V1, rd + pass); + gen_neon_addl(size); + } + neon_store_reg64(cpu_V0, rd + pass); + } + break; + case 33: /* VTRN */ + if (size == 2) { + for (n = 0; n < (q ? 4 : 2); n += 2) { + tmp = neon_load_reg(rm, n); + tmp2 = neon_load_reg(rd, n + 1); + neon_store_reg(rm, n, tmp2); + neon_store_reg(rd, n + 1, tmp); + } + } else { + goto elementwise; + } + break; + case 34: /* VUZP */ + /* Reg Before After + Rd A3 A2 A1 A0 B2 B0 A2 A0 + Rm B3 B2 B1 B0 B3 B1 A3 A1 + */ + if (size == 3) + return 1; + gen_neon_unzip(rd, q, 0, size); + gen_neon_unzip(rm, q, 4, size); + if (q) { + static int unzip_order_q[8] = + {0, 2, 4, 6, 1, 3, 5, 7}; + for (n = 0; n < 8; n++) { + int reg = (n < 4) ? rd : rm; + tmp = neon_load_scratch(unzip_order_q[n]); + neon_store_reg(reg, n % 4, tmp); + } + } else { + static int unzip_order[4] = + {0, 4, 1, 5}; + for (n = 0; n < 4; n++) { + int reg = (n < 2) ? rd : rm; + tmp = neon_load_scratch(unzip_order[n]); + neon_store_reg(reg, n % 2, tmp); + } + } + break; + case 35: /* VZIP */ + /* Reg Before After + Rd A3 A2 A1 A0 B1 A1 B0 A0 + Rm B3 B2 B1 B0 B3 A3 B2 A2 + */ + if (size == 3) + return 1; + count = (q ? 4 : 2); + for (n = 0; n < count; n++) { + tmp = neon_load_reg(rd, n); + tmp2 = neon_load_reg(rd, n); + switch (size) { + case 0: gen_neon_zip_u8(tmp, tmp2); break; + case 1: gen_neon_zip_u16(tmp, tmp2); break; + case 2: /* no-op */; break; + default: abort(); + } + neon_store_scratch(n * 2, tmp); + neon_store_scratch(n * 2 + 1, tmp2); + } + for (n = 0; n < count * 2; n++) { + int reg = (n < count) ? rd : rm; + tmp = neon_load_scratch(n); + neon_store_reg(reg, n % count, tmp); + } + break; + case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ + if (size == 3) + return 1; + TCGV_UNUSED(tmp2); + for (pass = 0; pass < 2; pass++) { + neon_load_reg64(cpu_V0, rm + pass); + tmp = new_tmp(); + if (op == 36 && q == 0) { + gen_neon_narrow(size, tmp, cpu_V0); + } else if (q) { + gen_neon_narrow_satu(size, tmp, cpu_V0); + } else { + gen_neon_narrow_sats(size, tmp, cpu_V0); + } + if (pass == 0) { + tmp2 = tmp; + } else { + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); + } + } + break; + case 38: /* VSHLL */ + if (q || size == 3) + return 1; + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + for (pass = 0; pass < 2; pass++) { + if (pass == 1) + tmp = tmp2; + gen_neon_widen(cpu_V0, tmp, size, 1); + neon_store_reg64(cpu_V0, rd + pass); + } + break; + case 44: /* VCVT.F16.F32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + tmp2 = new_tmp(); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0)); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1)); + gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp2, tmp2, tmp); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2)); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3)); + neon_store_reg(rd, 0, tmp2); + tmp2 = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp2, tmp2, tmp); + neon_store_reg(rd, 1, tmp2); + dead_tmp(tmp); + break; + case 46: /* VCVT.F32.F16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp3 = new_tmp(); + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + tcg_gen_ext16u_i32(tmp3, tmp); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0)); + tcg_gen_shri_i32(tmp3, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1)); + dead_tmp(tmp); + tcg_gen_ext16u_i32(tmp3, tmp2); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2)); + tcg_gen_shri_i32(tmp3, tmp2, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3)); + dead_tmp(tmp2); + dead_tmp(tmp3); + break; + default: + elementwise: + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op == 30 || op == 31 || op >= 58) { + tcg_gen_ld_f32(cpu_F0s, cpu_env, + neon_reg_offset(rm, pass)); + TCGV_UNUSED(tmp); + } else { + tmp = neon_load_reg(rm, pass); + } + switch (op) { + case 1: /* VREV32 */ + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_swap_half(tmp); break; + default: return 1; + } + break; + case 2: /* VREV16 */ + if (size != 0) + return 1; + gen_rev16(tmp); + break; + case 8: /* CLS */ + switch (size) { + case 0: gen_helper_neon_cls_s8(tmp, tmp); break; + case 1: gen_helper_neon_cls_s16(tmp, tmp); break; + case 2: gen_helper_neon_cls_s32(tmp, tmp); break; + default: return 1; + } + break; + case 9: /* CLZ */ + switch (size) { + case 0: gen_helper_neon_clz_u8(tmp, tmp); break; + case 1: gen_helper_neon_clz_u16(tmp, tmp); break; + case 2: gen_helper_clz(tmp, tmp); break; + default: return 1; + } + break; + case 10: /* CNT */ + if (size != 0) + return 1; + gen_helper_neon_cnt_u8(tmp, tmp); + break; + case 11: /* VNOT */ + if (size != 0) + return 1; + tcg_gen_not_i32(tmp, tmp); + break; + case 14: /* VQABS */ + switch (size) { + case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break; + case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break; + case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break; + default: return 1; + } + break; + case 15: /* VQNEG */ + switch (size) { + case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break; + case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break; + case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break; + default: return 1; + } + break; + case 16: case 19: /* VCGT #0, VCLE #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + if (op == 19) + tcg_gen_not_i32(tmp, tmp); + break; + case 17: case 20: /* VCGE #0, VCLT #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + if (op == 20) + tcg_gen_not_i32(tmp, tmp); + break; + case 18: /* VCEQ #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + break; + case 22: /* VABS */ + switch(size) { + case 0: gen_helper_neon_abs_s8(tmp, tmp); break; + case 1: gen_helper_neon_abs_s16(tmp, tmp); break; + case 2: tcg_gen_abs_i32(tmp, tmp); break; + default: return 1; + } + break; + case 23: /* VNEG */ + if (size == 3) + return 1; + tmp2 = tcg_const_i32(0); + gen_neon_rsb(size, tmp, tmp2); + tcg_temp_free(tmp2); + break; + case 24: case 27: /* Float VCGT #0, Float VCLE #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cgt_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + if (op == 27) + tcg_gen_not_i32(tmp, tmp); + break; + case 25: case 28: /* Float VCGE #0, Float VCLT #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cge_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + if (op == 28) + tcg_gen_not_i32(tmp, tmp); + break; + case 26: /* Float VCEQ #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_ceq_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + break; + case 30: /* Float VABS */ + gen_vfp_abs(0); + break; + case 31: /* Float VNEG */ + gen_vfp_neg(0); + break; + case 32: /* VSWP */ + tmp2 = neon_load_reg(rd, pass); + neon_store_reg(rm, pass, tmp2); + break; + case 33: /* VTRN */ + tmp2 = neon_load_reg(rd, pass); + switch (size) { + case 0: gen_neon_trn_u8(tmp, tmp2); break; + case 1: gen_neon_trn_u16(tmp, tmp2); break; + case 2: abort(); + default: return 1; + } + neon_store_reg(rm, pass, tmp2); + break; + case 56: /* Integer VRECPE */ + gen_helper_recpe_u32(tmp, tmp, cpu_env); + break; + case 57: /* Integer VRSQRTE */ + gen_helper_rsqrte_u32(tmp, tmp, cpu_env); + break; + case 58: /* Float VRECPE */ + gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); + break; + case 59: /* Float VRSQRTE */ + gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); + break; + case 60: /* VCVT.F32.S32 */ + gen_vfp_tosiz(0); + break; + case 61: /* VCVT.F32.U32 */ + gen_vfp_touiz(0); + break; + case 62: /* VCVT.S32.F32 */ + gen_vfp_sito(0); + break; + case 63: /* VCVT.U32.F32 */ + gen_vfp_uito(0); + break; + default: + /* Reserved: 21, 29, 39-56 */ + return 1; + } + if (op == 30 || op == 31 || op >= 58) { + tcg_gen_st_f32(cpu_F0s, cpu_env, + neon_reg_offset(rd, pass)); + } else { + neon_store_reg(rd, pass, tmp); + } + } + break; + } + } else if ((insn & (1 << 10)) == 0) { + /* VTBL, VTBX. */ + n = ((insn >> 5) & 0x18) + 8; + if (insn & (1 << 6)) { + tmp = neon_load_reg(rd, 0); + } else { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } + tmp2 = neon_load_reg(rm, 0); + tmp4 = tcg_const_i32(rn); + tmp5 = tcg_const_i32(n); + gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5); + dead_tmp(tmp); + if (insn & (1 << 6)) { + tmp = neon_load_reg(rd, 1); + } else { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } + tmp3 = neon_load_reg(rm, 1); + gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5); + tcg_temp_free_i32(tmp5); + tcg_temp_free_i32(tmp4); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp3); + dead_tmp(tmp); + } else if ((insn & 0x380) == 0) { + /* VDUP */ + if (insn & (1 << 19)) { + tmp = neon_load_reg(rm, 1); + } else { + tmp = neon_load_reg(rm, 0); + } + if (insn & (1 << 16)) { + gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8); + } else if (insn & (1 << 17)) { + if ((insn >> 18) & 1) + gen_neon_dup_high16(tmp); + else + gen_neon_dup_low16(tmp); + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rd, pass, tmp2); + } + dead_tmp(tmp); + } else { + return 1; + } + } + } + return 0; +} + +static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn) +{ + int crn = (insn >> 16) & 0xf; + int crm = insn & 0xf; + int op1 = (insn >> 21) & 7; + int op2 = (insn >> 5) & 7; + int rt = (insn >> 12) & 0xf; + TCGv tmp; + + if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { + if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { + /* TEECR */ + if (IS_USER(s)) + return 1; + tmp = load_cpu_field(teecr); + store_reg(s, rt, tmp); + return 0; + } + if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { + /* TEEHBR */ + if (IS_USER(s) && (env->teecr & 1)) + return 1; + tmp = load_cpu_field(teehbr); + store_reg(s, rt, tmp); + return 0; + } + } + fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n", + op1, crn, crm, op2); + return 1; +} + +static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn) +{ + int crn = (insn >> 16) & 0xf; + int crm = insn & 0xf; + int op1 = (insn >> 21) & 7; + int op2 = (insn >> 5) & 7; + int rt = (insn >> 12) & 0xf; + TCGv tmp; + + if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { + if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { + /* TEECR */ + if (IS_USER(s)) + return 1; + tmp = load_reg(s, rt); + gen_helper_set_teecr(cpu_env, tmp); + dead_tmp(tmp); + return 0; + } + if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { + /* TEEHBR */ + if (IS_USER(s) && (env->teecr & 1)) + return 1; + tmp = load_reg(s, rt); + store_cpu_field(tmp, teehbr); + return 0; + } + } + fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n", + op1, crn, crm, op2); + return 1; +} + +static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int cpnum; + + cpnum = (insn >> 8) & 0xf; + if (arm_feature(env, ARM_FEATURE_XSCALE) + && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum))) + return 1; + + switch (cpnum) { + case 0: + case 1: + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + return disas_iwmmxt_insn(env, s, insn); + } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { + return disas_dsp_insn(env, s, insn); + } + return 1; + case 10: + case 11: + return disas_vfp_insn (env, s, insn); + case 14: + /* Coprocessors 7-15 are architecturally reserved by ARM. + Unfortunately Intel decided to ignore this. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto board; + if (insn & (1 << 20)) + return disas_cp14_read(env, s, insn); + else + return disas_cp14_write(env, s, insn); + case 15: + return disas_cp15_insn (env, s, insn); + default: + board: + /* Unknown coprocessor. See if the board has hooked it. */ + return disas_cp_insn (env, s, insn); + } +} + + +/* Store a 64-bit value to a register pair. Clobbers val. */ +static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rlow, tmp); + tmp = new_tmp(); + tcg_gen_shri_i64(val, val, 32); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rhigh, tmp); +} + +/* load a 32-bit value from a register and perform a 64-bit accumulate. */ +static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow) +{ + TCGv_i64 tmp; + TCGv tmp2; + + /* Load value and extend to 64 bits. */ + tmp = tcg_temp_new_i64(); + tmp2 = load_reg(s, rlow); + tcg_gen_extu_i32_i64(tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* load and add a 64-bit value from a register pair. */ +static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) +{ + TCGv_i64 tmp; + TCGv tmpl; + TCGv tmph; + + /* Load 64-bit value rd:rn. */ + tmpl = load_reg(s, rlow); + tmph = load_reg(s, rhigh); + tmp = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(tmp, tmpl, tmph); + dead_tmp(tmpl); + dead_tmp(tmph); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* Set N and Z flags from a 64-bit value. */ +static void gen_logicq_cc(TCGv_i64 val) +{ + TCGv tmp = new_tmp(); + gen_helper_logicq_cc(tmp, val); + gen_logic_CC(tmp); + dead_tmp(tmp); +} + +/* Load/Store exclusive instructions are implemented by remembering + the value/address loaded, and seeing if these are the same + when the store is performed. This should be is sufficient to implement + the architecturally mandated semantics, and avoids having to monitor + regular stores. + + In system emulation mode only one CPU will be running at once, so + this sequence is effectively atomic. In user emulation mode we + throw an exception and handle the atomic operation elsewhere. */ +static void gen_load_exclusive(DisasContext *s, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_mov_i32(cpu_exclusive_val, tmp); + store_reg(s, rt, tmp); + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + tcg_gen_mov_i32(cpu_exclusive_high, tmp); + store_reg(s, rt2, tmp); + } + tcg_gen_mov_i32(cpu_exclusive_addr, addr); +} + +static void gen_clrex(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} + +#ifdef CONFIG_USER_ONLY +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + tcg_gen_mov_i32(cpu_exclusive_test, addr); + tcg_gen_movi_i32(cpu_exclusive_info, + size | (rd << 4) | (rt << 8) | (rt2 << 12)); + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_STREX); + s->is_jmp = DISAS_JUMP; +} +#else +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + int done_label; + int fail_label; + + /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) { + [addr] = {Rt}; + {Rd} = 0; + } else { + {Rd} = 1; + } */ + fail_label = gen_new_label(); + done_label = gen_new_label(); + tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label); + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label); + dead_tmp(tmp); + if (size == 3) { + TCGv tmp2 = new_tmp(); + tcg_gen_addi_i32(tmp2, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(tmp2); + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label); + dead_tmp(tmp); + } + tmp = load_reg(s, rt); + switch (size) { + case 0: + gen_st8(tmp, addr, IS_USER(s)); + break; + case 1: + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: + case 3: + gen_st32(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rt2); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_movi_i32(cpu_R[rd], 0); + tcg_gen_br(done_label); + gen_set_label(fail_label); + tcg_gen_movi_i32(cpu_R[rd], 1); + gen_set_label(done_label); + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} +#endif + +static void disas_arm_insn(CPUState * env, DisasContext *s) +{ + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; + TCGv_i64 tmp64; + + insn = ldl_code(s->pc); + s->pc += 4; + + /* M variants do not implement ARM mode. */ + if (IS_M(env)) + goto illegal_op; + cond = insn >> 28; + if (cond == 0xf){ + /* Unconditional instructions. */ + if (((insn >> 25) & 7) == 1) { + /* NEON Data processing. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0f100000) == 0x04000000) { + /* NEON load/store. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_ls_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0d70f000) == 0x0550f000) + return; /* PLD */ + else if ((insn & 0x0ffffdff) == 0x01010000) { + ARCH(6); + /* setend */ + if (insn & (1 << 9)) { + /* BE8 mode not implemented. */ + goto illegal_op; + } + return; + } else if ((insn & 0x0fffff00) == 0x057ff000) { + switch ((insn >> 4) & 0xf) { + case 1: /* clrex */ + ARCH(6K); + gen_clrex(s); + return; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + ARCH(7); + /* We don't emulate caches so these are a no-op. */ + return; + default: + goto illegal_op; + } + } else if ((insn & 0x0e5fffe0) == 0x084d0500) { + /* srs */ + int32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + op1 = (insn & 0x1f); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + addr = load_reg(s, 13); + } else { + addr = new_tmp(); + tmp = tcg_const_i32(op1); + gen_helper_get_r13_banked(addr, cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = -4; break; /* DA */ + case 1: offset = 0; break; /* IA */ + case 2: offset = -8; break; /* DB */ + case 3: offset = 4; break; /* IB */ + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tmp = load_cpu_field(spsr); + tcg_gen_addi_i32(addr, addr, 4); + gen_st32(tmp, addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -8; break; + case 1: offset = 4; break; + case 2: offset = -4; break; + case 3: offset = 0; break; + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + store_reg(s, 13, addr); + } else { + tmp = tcg_const_i32(op1); + gen_helper_set_r13_banked(cpu_env, tmp, addr); + tcg_temp_free_i32(tmp); + dead_tmp(addr); + } + } else { + dead_tmp(addr); + } + } else if ((insn & 0x0e5fffe0) == 0x081d0a00) { + /* rfe */ + int32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + rn = (insn >> 16) & 0xf; + addr = load_reg(s, rn); + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = -4; break; /* DA */ + case 1: offset = 0; break; /* IA */ + case 2: offset = -8; break; /* DB */ + case 3: offset = 4; break; /* IB */ + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -8; break; + case 1: offset = 4; break; + case 2: offset = -4; break; + case 3: offset = 0; break; + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + gen_rfe(s, tmp, tmp2); + return; + } else if ((insn & 0x0e000000) == 0x0a000000) { + /* branch link and change to thumb (blx ) */ + int32_t offset; + + val = (uint32_t)s->pc; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); + /* Sign-extend the 24-bit offset */ + offset = (((int32_t)insn) << 8) >> 8; + /* offset * 4 + bit24 * 2 + (thumb bit) */ + val += (offset << 2) | ((insn >> 23) & 2) | 1; + /* pipeline offset */ + val += 4; + gen_bx_im(s, val); + return; + } else if ((insn & 0x0e000f00) == 0x0c000100) { + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + /* iWMMXt register transfer. */ + if (env->cp15.c15_cpar & (1 << 1)) + if (!disas_iwmmxt_insn(env, s, insn)) + return; + } + } else if ((insn & 0x0fe00000) == 0x0c400000) { + /* Coprocessor double register transfer. */ + } else if ((insn & 0x0f000010) == 0x0e000010) { + /* Additional coprocessor register transfer. */ + } else if ((insn & 0x0ff10020) == 0x01000000) { + uint32_t mask; + uint32_t val; + /* cps (privileged) */ + if (IS_USER(s)) + return; + mask = val = 0; + if (insn & (1 << 19)) { + if (insn & (1 << 8)) + mask |= CPSR_A; + if (insn & (1 << 7)) + mask |= CPSR_I; + if (insn & (1 << 6)) + mask |= CPSR_F; + if (insn & (1 << 18)) + val |= mask; + } + if (insn & (1 << 17)) { + mask |= CPSR_M; + val |= (insn & 0x1f); + } + if (mask) { + gen_set_psr_im(s, mask, 0, val); + } + return; + } + goto illegal_op; + } + if (cond != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + } + if ((insn & 0x0f900000) == 0x03000000) { + if ((insn & (1 << 21)) == 0) { + ARCH(6T2); + rd = (insn >> 12) & 0xf; + val = ((insn >> 4) & 0xf000) | (insn & 0xfff); + if ((insn & (1 << 22)) == 0) { + /* MOVW */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else { + /* MOVT */ + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, val << 16); + } + store_reg(s, rd, tmp); + } else { + if (((insn >> 12) & 0xf) != 0xf) + goto illegal_op; + if (((insn >> 16) & 0xf) == 0) { + gen_nop_hint(s, insn & 0xff); + } else { + /* CPSR = immediate */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + i = ((insn & (1 << 22)) != 0); + if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val)) + goto illegal_op; + } + } + } else if ((insn & 0x0f900000) == 0x01000000 + && (insn & 0x00000090) != 0x00000090) { + /* miscellaneous instructions */ + op1 = (insn >> 21) & 3; + sh = (insn >> 4) & 0xf; + rm = insn & 0xf; + switch (sh) { + case 0x0: /* move program status register */ + if (op1 & 1) { + /* PSR = reg */ + tmp = load_reg(s, rm); + i = ((op1 & 2) != 0); + if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp)) + goto illegal_op; + } else { + /* reg = PSR */ + rd = (insn >> 12) & 0xf; + if (op1 & 2) { + if (IS_USER(s)) + goto illegal_op; + tmp = load_cpu_field(spsr); + } else { + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + } + store_reg(s, rd, tmp); + } + break; + case 0x1: + if (op1 == 1) { + /* branch/exchange thumb (bx). */ + tmp = load_reg(s, rm); + gen_bx(s, tmp); + } else if (op1 == 3) { + /* clz */ + rd = (insn >> 12) & 0xf; + tmp = load_reg(s, rm); + gen_helper_clz(tmp, tmp); + store_reg(s, rd, tmp); + } else { + goto illegal_op; + } + break; + case 0x2: + if (op1 == 1) { + ARCH(5J); /* bxj */ + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, rm); + gen_bx(s, tmp); + } else { + goto illegal_op; + } + break; + case 0x3: + if (op1 != 1) + goto illegal_op; + + /* branch link/exchange thumb (blx) */ + tmp = load_reg(s, rm); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + break; + case 0x5: /* saturating add/subtract */ + rd = (insn >> 12) & 0xf; + rn = (insn >> 16) & 0xf; + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rn); + if (op1 & 2) + gen_helper_double_saturate(tmp2, tmp2); + if (op1 & 1) + gen_helper_sub_saturate(tmp, tmp, tmp2); + else + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 7: /* bkpt */ + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_BKPT); + s->is_jmp = DISAS_JUMP; + break; + case 0x8: /* signed multiply */ + case 0xa: + case 0xc: + case 0xe: + rs = (insn >> 8) & 0xf; + rn = (insn >> 12) & 0xf; + rd = (insn >> 16) & 0xf; + if (op1 == 1) { + /* (32 * 16) >> 16 */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + if (sh & 4) + tcg_gen_sari_i32(tmp2, tmp2, 16); + else + gen_sxth(tmp2); + tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp64, tmp64, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if ((sh & 2) == 0) { + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + } else { + /* 16 * 16 */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_mulxy(tmp, tmp2, sh & 2, sh & 4); + dead_tmp(tmp2); + if (op1 == 2) { + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rn, rd); + gen_storeq_reg(s, rn, rd, tmp64); + tcg_temp_free_i64(tmp64); + } else { + if (op1 == 0) { + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + } + } + break; + default: + goto illegal_op; + } + } else if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { + int set_cc, logic_cc, shiftop; + + op1 = (insn >> 21) & 0xf; + set_cc = (insn >> 20) & 1; + logic_cc = table_logic_cc[op1] & set_cc; + + /* data processing instruction */ + if (insn & (1 << 25)) { + /* immediate operand */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) { + val = (val >> shift) | (val << (32 - shift)); + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + if (logic_cc && shift) { + gen_set_CF_bit31(tmp2); + } + } else { + /* register */ + rm = (insn) & 0xf; + tmp2 = load_reg(s, rm); + shiftop = (insn >> 5) & 3; + if (!(insn & (1 << 4))) { + shift = (insn >> 7) & 0x1f; + gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); + } else { + rs = (insn >> 8) & 0xf; + tmp = load_reg(s, rs); + gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc); + } + } + if (op1 != 0x0f && op1 != 0x0d) { + rn = (insn >> 16) & 0xf; + tmp = load_reg(s, rn); + } else { + TCGV_UNUSED(tmp); + } + rd = (insn >> 12) & 0xf; + switch(op1) { + case 0x00: + tcg_gen_and_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x01: + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x02: + if (set_cc && rd == 15) { + /* SUBS r15, ... is used for exception return. */ + if (IS_USER(s)) { + goto illegal_op; + } + gen_helper_sub_cc(tmp, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (set_cc) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + } + break; + case 0x03: + if (set_cc) { + gen_helper_sub_cc(tmp, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x04: + if (set_cc) { + gen_helper_add_cc(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x05: + if (set_cc) { + gen_helper_adc_cc(tmp, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x06: + if (set_cc) { + gen_helper_sbc_cc(tmp, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x07: + if (set_cc) { + gen_helper_sbc_cc(tmp, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x08: + if (set_cc) { + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x09: + if (set_cc) { + tcg_gen_xor_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x0a: + if (set_cc) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0b: + if (set_cc) { + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0c: + tcg_gen_or_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x0d: + if (logic_cc && rd == 15) { + /* MOVS r15, ... is used for exception return. */ + if (IS_USER(s)) { + goto illegal_op; + } + gen_exception_return(s, tmp2); + } else { + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(env, s, rd, tmp2); + } + break; + case 0x0e: + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + default: + case 0x0f: + tcg_gen_not_i32(tmp2, tmp2); + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(env, s, rd, tmp2); + break; + } + if (op1 != 0x0f && op1 != 0x0d) { + dead_tmp(tmp2); + } + } else { + /* other instructions */ + op1 = (insn >> 24) & 0xf; + switch(op1) { + case 0x0: + case 0x1: + /* multiplies, extra load/stores */ + sh = (insn >> 5) & 3; + if (sh == 0) { + if (op1 == 0x0) { + rd = (insn >> 16) & 0xf; + rn = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + rm = (insn) & 0xf; + op1 = (insn >> 20) & 0xf; + switch (op1) { + case 0: case 1: case 2: case 3: case 6: + /* 32 bit mul */ + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (insn & (1 << 22)) { + /* Subtract (mls) */ + ARCH(6T2); + tmp2 = load_reg(s, rn); + tcg_gen_sub_i32(tmp, tmp2, tmp); + dead_tmp(tmp2); + } else if (insn & (1 << 21)) { + /* Add */ + tmp2 = load_reg(s, rn); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + if (insn & (1 << 20)) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + break; + default: + /* 64 bit mul */ + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + if (insn & (1 << 22)) + tmp64 = gen_muls_i64_i32(tmp, tmp2); + else + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + if (insn & (1 << 21)) /* mult accumulate */ + gen_addq(s, tmp64, rn, rd); + if (!(insn & (1 << 23))) { /* double accumulate */ + ARCH(6); + gen_addq_lo(s, tmp64, rn); + gen_addq_lo(s, tmp64, rd); + } + if (insn & (1 << 20)) + gen_logicq_cc(tmp64); + gen_storeq_reg(s, rn, rd, tmp64); + tcg_temp_free_i64(tmp64); + break; + } + } else { + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (insn & (1 << 23)) { + /* load/store exclusive */ + op1 = (insn >> 21) & 0x3; + if (op1) + ARCH(6K); + else + ARCH(6); + addr = tcg_temp_local_new_i32(); + load_reg_var(s, addr, rn); + if (insn & (1 << 20)) { + switch (op1) { + case 0: /* ldrex */ + gen_load_exclusive(s, rd, 15, addr, 2); + break; + case 1: /* ldrexd */ + gen_load_exclusive(s, rd, rd + 1, addr, 3); + break; + case 2: /* ldrexb */ + gen_load_exclusive(s, rd, 15, addr, 0); + break; + case 3: /* ldrexh */ + gen_load_exclusive(s, rd, 15, addr, 1); + break; + default: + abort(); + } + } else { + rm = insn & 0xf; + switch (op1) { + case 0: /* strex */ + gen_store_exclusive(s, rd, rm, 15, addr, 2); + break; + case 1: /* strexd */ + gen_store_exclusive(s, rd, rm, rm + 1, addr, 3); + break; + case 2: /* strexb */ + gen_store_exclusive(s, rd, rm, 15, addr, 0); + break; + case 3: /* strexh */ + gen_store_exclusive(s, rd, rm, 15, addr, 1); + break; + default: + abort(); + } + } + tcg_temp_free(addr); + } else { + /* SWP instruction */ + rm = (insn) & 0xf; + + /* ??? This is not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ + addr = load_reg(s, rn); + tmp = load_reg(s, rm); + if (insn & (1 << 22)) { + tmp2 = gen_ld8u(addr, IS_USER(s)); + gen_st8(tmp, addr, IS_USER(s)); + } else { + tmp2 = gen_ld32(addr, IS_USER(s)); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + store_reg(s, rd, tmp2); + } + } + } else { + int address_offset; + int load; + /* Misc load/store */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + addr = load_reg(s, rn); + if (insn & (1 << 24)) + gen_add_datah_offset(s, insn, 0, addr); + address_offset = 0; + if (insn & (1 << 20)) { + /* load */ + switch(sh) { + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld8s(addr, IS_USER(s)); + break; + default: + case 3: + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + load = 1; + } else if (sh & 2) { + /* doubleword */ + if (sh & 1) { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd + 1); + gen_st32(tmp, addr, IS_USER(s)); + load = 0; + } else { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + rd++; + load = 1; + } + address_offset = -4; + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); + load = 0; + } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. + ldrd with base writeback is is undefined if the + destination and index registers overlap. */ + if (!(insn & (1 << 24))) { + gen_add_datah_offset(s, insn, address_offset, addr); + store_reg(s, rn, addr); + } else if (insn & (1 << 21)) { + if (address_offset) + tcg_gen_addi_i32(addr, addr, address_offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + if (load) { + /* Complete the load. */ + store_reg(s, rd, tmp); + } + } + break; + case 0x4: + case 0x5: + goto do_ldst; + case 0x6: + case 0x7: + if (insn & (1 << 4)) { + ARCH(6); + /* Armv6 Media instructions. */ + rm = insn & 0xf; + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + switch ((insn >> 23) & 3) { + case 0: /* Parallel add/subtract. */ + op1 = (insn >> 20) & 7; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + sh = (insn >> 5) & 7; + if ((op1 & 3) == 0 || sh == 5 || sh == 6) + goto illegal_op; + gen_arm_parallel_addsub(op1, sh, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 1: + if ((insn & 0x00700020) == 0) { + /* Halfword pack. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (insn & (1 << 6)) { + /* pkhtb */ + if (shift == 0) + shift = 31; + tcg_gen_sari_i32(tmp2, tmp2, shift); + tcg_gen_andi_i32(tmp, tmp, 0xffff0000); + tcg_gen_ext16u_i32(tmp2, tmp2); + } else { + /* pkhbt */ + if (shift) + tcg_gen_shli_i32(tmp2, tmp2, shift); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000); + } + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x00200020) == 0x00200000) { + /* [us]sat */ + tmp = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (insn & (1 << 6)) { + if (shift == 0) + shift = 31; + tcg_gen_sari_i32(tmp, tmp, shift); + } else { + tcg_gen_shli_i32(tmp, tmp, shift); + } + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) + gen_helper_usat(tmp, tmp, tmp2); + else + gen_helper_ssat(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); + } else if ((insn & 0x00300fe0) == 0x00200f20) { + /* [us]sat16 */ + tmp = load_reg(s, rm); + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) + gen_helper_usat16(tmp, tmp, tmp2); + else + gen_helper_ssat16(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); + } else if ((insn & 0x00700fe0) == 0x00000fa0) { + /* Select bytes. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x000003e0) == 0x00000060) { + tmp = load_reg(s, rm); + shift = (insn >> 10) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + tcg_gen_rotri_i32(tmp, tmp, shift * 8); + op1 = (insn >> 20) & 7; + switch (op1) { + case 0: gen_sxtb16(tmp); break; + case 2: gen_sxtb(tmp); break; + case 3: gen_sxth(tmp); break; + case 4: gen_uxtb16(tmp); break; + case 6: gen_uxtb(tmp); break; + case 7: gen_uxth(tmp); break; + default: goto illegal_op; + } + if (rn != 15) { + tmp2 = load_reg(s, rn); + if ((op1 & 3) == 0) { + gen_add16(tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + } + store_reg(s, rd, tmp); + } else if ((insn & 0x003f0f60) == 0x003f0f20) { + /* rev */ + tmp = load_reg(s, rm); + if (insn & (1 << 22)) { + if (insn & (1 << 7)) { + gen_revsh(tmp); + } else { + ARCH(6T2); + gen_helper_rbit(tmp, tmp); + } + } else { + if (insn & (1 << 7)) + gen_rev16(tmp); + else + tcg_gen_bswap32_i32(tmp, tmp); + } + store_reg(s, rd, tmp); + } else { + goto illegal_op; + } + break; + case 2: /* Multiplies (Type 3). */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + if (insn & (1 << 20)) { + /* Signed multiply most significant [accumulate]. */ + tmp64 = gen_muls_i64_i32(tmp, tmp2); + if (insn & (1 << 5)) + tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u); + tcg_gen_shri_i64(tmp64, tmp64, 32); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if (rd != 15) { + tmp2 = load_reg(s, rd); + if (insn & (1 << 6)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + } else { + if (insn & (1 << 5)) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + /* This addition cannot overflow. */ + if (insn & (1 << 6)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + if (insn & (1 << 22)) { + /* smlald, smlsld */ + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rd, rn); + gen_storeq_reg(s, rd, rn, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* smuad, smusd, smlad, smlsd */ + if (rd != 15) + { + tmp2 = load_reg(s, rd); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + } + } + break; + case 3: + op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); + switch (op1) { + case 0: /* Unsigned sum of absolute differences. */ + ARCH(6); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rd != 15) { + tmp2 = load_reg(s, rd); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + break; + case 0x20: case 0x24: case 0x28: case 0x2c: + /* Bitfield insert/clear. */ + ARCH(6T2); + shift = (insn >> 7) & 0x1f; + i = (insn >> 16) & 0x1f; + i = i + 1 - shift; + if (rm == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rm); + } + if (i != 32) { + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + break; + case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ + case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ + ARCH(6T2); + tmp = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + i = ((insn >> 16) & 0x1f) + 1; + if (shift + i > 32) + goto illegal_op; + if (i < 32) { + if (op1 & 0x20) { + gen_ubfx(tmp, shift, (1u << i) - 1); + } else { + gen_sbfx(tmp, shift, i); + } + } + store_reg(s, rd, tmp); + break; + default: + goto illegal_op; + } + break; + } + break; + } + do_ldst: + /* Check for undefined extension instructions + * per the ARM Bible IE: + * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + */ + sh = (0xf << 20) | (0xf << 4); + if (op1 == 0x7 && ((insn & sh) == sh)) + { + goto illegal_op; + } + /* load/store byte/word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + tmp2 = load_reg(s, rn); + i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); + if (insn & (1 << 24)) + gen_add_data_offset(s, insn, tmp2); + if (insn & (1 << 20)) { + /* load */ + if (insn & (1 << 22)) { + tmp = gen_ld8u(tmp2, i); + } else { + tmp = gen_ld32(tmp2, i); + } + } else { + /* store */ + tmp = load_reg(s, rd); + if (insn & (1 << 22)) + gen_st8(tmp, tmp2, i); + else + gen_st32(tmp, tmp2, i); + } + if (!(insn & (1 << 24))) { + gen_add_data_offset(s, insn, tmp2); + store_reg(s, rn, tmp2); + } else if (insn & (1 << 21)) { + store_reg(s, rn, tmp2); + } else { + dead_tmp(tmp2); + } + if (insn & (1 << 20)) { + /* Complete the load. */ + if (rd == 15) + gen_bx(s, tmp); + else + store_reg(s, rd, tmp); + } + break; + case 0x08: + case 0x09: + { + int j, n, user, loaded_base; + TCGv loaded_var; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + user = 0; + if (insn & (1 << 22)) { + if (IS_USER(s)) + goto illegal_op; /* only usable in supervisor mode */ + + if ((insn & (1 << 15)) == 0) + user = 1; + } + rn = (insn >> 16) & 0xf; + addr = load_reg(s, rn); + + /* compute total size */ + loaded_base = 0; + TCGV_UNUSED(loaded_var); + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* post increment */ + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { + /* post decrement */ + if (n != 1) + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + if (i == 15) { + gen_bx(s, tmp); + } else if (user) { + tmp2 = tcg_const_i32(i); + gen_helper_set_user_reg(tmp2, tmp); + tcg_temp_free_i32(tmp2); + dead_tmp(tmp); + } else if (i == rn) { + loaded_var = tmp; + loaded_base = 1; + } else { + store_reg(s, i, tmp); + } + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 8 */ + val = (long)s->pc + 4; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else if (user) { + tmp = new_tmp(); + tmp2 = tcg_const_i32(i); + gen_helper_get_user_reg(tmp, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, i); + } + gen_st32(tmp, addr, IS_USER(s)); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + tcg_gen_addi_i32(addr, addr, 4); + } + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + if (loaded_base) { + store_reg(s, rn, loaded_var); + } + if ((insn & (1 << 22)) && !user) { + /* Restore CPSR from SPSR. */ + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; + } + } + break; + case 0xa: + case 0xb: + { + int32_t offset; + + /* branch (and link) */ + val = (int32_t)s->pc; + if (insn & (1 << 24)) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); + } + offset = (((int32_t)insn << 8) >> 8); + val += (offset << 2) + 4; + gen_jmp(s, val); + } + break; + case 0xc: + case 0xd: + case 0xe: + /* Coprocessor. */ + if (disas_coproc_insn(env, s, insn)) + goto illegal_op; + break; + case 0xf: + /* swi */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SWI; + break; + default: + illegal_op: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; + break; + } + } +} + +/* Return true if this is a Thumb-2 logical op. */ +static int +thumb2_logic_op(int op) +{ + return (op < 8); +} + +/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero + then set condition code flags based on the result of the operation. + If SHIFTER_OUT is nonzero then set the carry flag for logical operations + to the high bit of T1. + Returns zero if the opcode is valid. */ + +static int +gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1) +{ + int logic_cc; + + logic_cc = 0; + switch (op) { + case 0: /* and */ + tcg_gen_and_i32(t0, t0, t1); + logic_cc = conds; + break; + case 1: /* bic */ + tcg_gen_andc_i32(t0, t0, t1); + logic_cc = conds; + break; + case 2: /* orr */ + tcg_gen_or_i32(t0, t0, t1); + logic_cc = conds; + break; + case 3: /* orn */ + tcg_gen_not_i32(t1, t1); + tcg_gen_or_i32(t0, t0, t1); + logic_cc = conds; + break; + case 4: /* eor */ + tcg_gen_xor_i32(t0, t0, t1); + logic_cc = conds; + break; + case 8: /* add */ + if (conds) + gen_helper_add_cc(t0, t0, t1); + else + tcg_gen_add_i32(t0, t0, t1); + break; + case 10: /* adc */ + if (conds) + gen_helper_adc_cc(t0, t0, t1); + else + gen_adc(t0, t1); + break; + case 11: /* sbc */ + if (conds) + gen_helper_sbc_cc(t0, t0, t1); + else + gen_sub_carry(t0, t0, t1); + break; + case 13: /* sub */ + if (conds) + gen_helper_sub_cc(t0, t0, t1); + else + tcg_gen_sub_i32(t0, t0, t1); + break; + case 14: /* rsb */ + if (conds) + gen_helper_sub_cc(t0, t1, t0); + else + tcg_gen_sub_i32(t0, t1, t0); + break; + default: /* 5, 6, 7, 9, 12, 15. */ + return 1; + } + if (logic_cc) { + gen_logic_CC(t0); + if (shifter_out) + gen_set_CF_bit31(t1); + } + return 0; +} + +/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction + is not legal. */ +static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) +{ + uint32_t insn, imm, shift, offset; + uint32_t rd, rn, rm, rs; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; + TCGv_i64 tmp64; + int op; + int shiftop; + int conds; + int logic_cc; + + if (!(arm_feature(env, ARM_FEATURE_THUMB2) + || arm_feature (env, ARM_FEATURE_M))) { + /* Thumb-1 cores may need to treat bl and blx as a pair of + 16-bit instructions to get correct prefetch abort behavior. */ + insn = insn_hw1; + if ((insn & (1 << 12)) == 0) { + /* Second half of blx. */ + offset = ((insn & 0x7ff) << 1); + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); + tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); + + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + return 0; + } + if (insn & (1 << 11)) { + /* Second half of bl. */ + offset = ((insn & 0x7ff) << 1) | 1; + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); + + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + return 0; + } + if ((s->pc & ~TARGET_PAGE_MASK) == 0) { + /* Instruction spans a page boundary. Implement it as two + 16-bit instructions in case the second half causes an + prefetch abort. */ + offset = ((int32_t)insn << 21) >> 9; + tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset); + return 0; + } + /* Fall through to 32-bit decode. */ + } + + insn = lduw_code(s->pc); + s->pc += 2; + insn |= (uint32_t)insn_hw1 << 16; + + if ((insn & 0xf800e800) != 0xf000e800) { + ARCH(6T2); + } + + rn = (insn >> 16) & 0xf; + rs = (insn >> 12) & 0xf; + rd = (insn >> 8) & 0xf; + rm = insn & 0xf; + switch ((insn >> 25) & 0xf) { + case 0: case 1: case 2: case 3: + /* 16-bit instructions. Should never happen. */ + abort(); + case 4: + if (insn & (1 << 22)) { + /* Other load/store, table branch. */ + if (insn & 0x01200000) { + /* Load/store doubleword. */ + if (rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc & ~3); + } else { + addr = load_reg(s, rn); + } + offset = (insn & 0xff) * 4; + if ((insn & (1 << 23)) == 0) + offset = -offset; + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, offset); + offset = 0; + } + if (insn & (1 << 20)) { + /* ldrd */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rs, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* strd */ + tmp = load_reg(s, rs); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + if (insn & (1 << 21)) { + /* Base writeback. */ + if (rn == 15) + goto illegal_op; + tcg_gen_addi_i32(addr, addr, offset - 4); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } else if ((insn & (1 << 23)) == 0) { + /* Load/store exclusive word. */ + addr = tcg_temp_local_new(); + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2); + if (insn & (1 << 20)) { + gen_load_exclusive(s, rs, 15, addr, 2); + } else { + gen_store_exclusive(s, rd, rs, 15, addr, 2); + } + tcg_temp_free(addr); + } else if ((insn & (1 << 6)) == 0) { + /* Table Branch. */ + if (rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc); + } else { + addr = load_reg(s, rn); + } + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); + if (insn & (1 << 4)) { + /* tbh */ + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + tmp = gen_ld16u(addr, IS_USER(s)); + } else { /* tbb */ + dead_tmp(tmp); + tmp = gen_ld8u(addr, IS_USER(s)); + } + dead_tmp(addr); + tcg_gen_shli_i32(tmp, tmp, 1); + tcg_gen_addi_i32(tmp, tmp, s->pc); + store_reg(s, 15, tmp); + } else { + /* Load/store exclusive byte/halfword/doubleword. */ + ARCH(7); + op = (insn >> 4) & 0x3; + if (op == 2) { + goto illegal_op; + } + addr = tcg_temp_local_new(); + load_reg_var(s, addr, rn); + if (insn & (1 << 20)) { + gen_load_exclusive(s, rs, rd, addr, op); + } else { + gen_store_exclusive(s, rm, rs, rd, addr, op); + } + tcg_temp_free(addr); + } + } else { + /* Load/store multiple, RFE, SRS. */ + if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { + /* Not available in user mode. */ + if (IS_USER(s)) + goto illegal_op; + if (insn & (1 << 20)) { + /* rfe */ + addr = load_reg(s, rn); + if ((insn & (1 << 24)) == 0) + tcg_gen_addi_i32(addr, addr, -8); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, 4); + } else { + tcg_gen_addi_i32(addr, addr, -4); + } + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + gen_rfe(s, tmp, tmp2); + } else { + /* srs */ + op = (insn & 0x1f); + if (op == (env->uncached_cpsr & CPSR_M)) { + addr = load_reg(s, 13); + } else { + addr = new_tmp(); + tmp = tcg_const_i32(op); + gen_helper_get_r13_banked(addr, cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + if ((insn & (1 << 24)) == 0) { + tcg_gen_addi_i32(addr, addr, -8); + } + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + gen_st32(tmp, addr, 0); + if (insn & (1 << 21)) { + if ((insn & (1 << 24)) == 0) { + tcg_gen_addi_i32(addr, addr, -4); + } else { + tcg_gen_addi_i32(addr, addr, 4); + } + if (op == (env->uncached_cpsr & CPSR_M)) { + store_reg(s, 13, addr); + } else { + tmp = tcg_const_i32(op); + gen_helper_set_r13_banked(cpu_env, tmp, addr); + tcg_temp_free_i32(tmp); + } + } else { + dead_tmp(addr); + } + } + } else { + int i; + /* Load/store multiple. */ + addr = load_reg(s, rn); + offset = 0; + for (i = 0; i < 16; i++) { + if (insn & (1 << i)) + offset += 4; + } + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, -offset); + } + + for (i = 0; i < 16; i++) { + if ((insn & (1 << i)) == 0) + continue; + if (insn & (1 << 20)) { + /* Load. */ + tmp = gen_ld32(addr, IS_USER(s)); + if (i == 15) { + gen_bx(s, tmp); + } else { + store_reg(s, i, tmp); + } + } else { + /* Store. */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, 4); + } + if (insn & (1 << 21)) { + /* Base register writeback. */ + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, -offset); + } + /* Fault if writeback register is in register list. */ + if (insn & (1 << rn)) + goto illegal_op; + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + } + break; + case 5: /* Data processing register constant shift. */ + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + tmp2 = load_reg(s, rm); + op = (insn >> 21) & 0xf; + shiftop = (insn >> 4) & 3; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + conds = (insn & (1 << 20)) != 0; + logic_cc = (conds && thumb2_logic_op(op)); + gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); + if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2)) + goto illegal_op; + dead_tmp(tmp2); + if (rd != 15) { + store_reg(s, rd, tmp); + } else { + dead_tmp(tmp); + } + break; + case 13: /* Misc data processing. */ + op = ((insn >> 22) & 6) | ((insn >> 7) & 1); + if (op < 4 && (insn & 0xf000) != 0xf000) + goto illegal_op; + switch (op) { + case 0: /* Register controlled shift. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if ((insn & 0x70) != 0) + goto illegal_op; + op = (insn >> 21) & 3; + logic_cc = (insn & (1 << 20)) != 0; + gen_arm_shift_reg(tmp, op, tmp2, logic_cc); + if (logic_cc) + gen_logic_CC(tmp); + store_reg_bx(env, s, rd, tmp); + break; + case 1: /* Sign/zero extend. */ + tmp = load_reg(s, rm); + shift = (insn >> 4) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + tcg_gen_rotri_i32(tmp, tmp, shift * 8); + op = (insn >> 20) & 7; + switch (op) { + case 0: gen_sxth(tmp); break; + case 1: gen_uxth(tmp); break; + case 2: gen_sxtb16(tmp); break; + case 3: gen_uxtb16(tmp); break; + case 4: gen_sxtb(tmp); break; + case 5: gen_uxtb(tmp); break; + default: goto illegal_op; + } + if (rn != 15) { + tmp2 = load_reg(s, rn); + if ((op >> 1) == 1) { + gen_add16(tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + } + store_reg(s, rd, tmp); + break; + case 2: /* SIMD add/subtract. */ + op = (insn >> 20) & 7; + shift = (insn >> 4) & 7; + if ((op & 3) == 3 || (shift & 3) == 3) + goto illegal_op; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + gen_thumb2_parallel_addsub(op, shift, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 3: /* Other data processing. */ + op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); + if (op < 4) { + /* Saturating add/subtract. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if (op & 2) + gen_helper_double_saturate(tmp, tmp); + if (op & 1) + gen_helper_sub_saturate(tmp, tmp2, tmp); + else + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); + } else { + tmp = load_reg(s, rn); + switch (op) { + case 0x0a: /* rbit */ + gen_helper_rbit(tmp, tmp); + break; + case 0x08: /* rev */ + tcg_gen_bswap32_i32(tmp, tmp); + break; + case 0x09: /* rev16 */ + gen_rev16(tmp); + break; + case 0x0b: /* revsh */ + gen_revsh(tmp); + break; + case 0x10: /* sel */ + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); + break; + case 0x18: /* clz */ + gen_helper_clz(tmp, tmp); + break; + default: + goto illegal_op; + } + } + store_reg(s, rd, tmp); + break; + case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ + op = (insn >> 4) & 0xf; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + switch ((insn >> 20) & 7) { + case 0: /* 32 x 32 -> 32 */ + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + if (op) + tcg_gen_sub_i32(tmp, tmp2, tmp); + else + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 1: /* 16 x 16 -> 32 */ + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 2: /* Dual multiply add. */ + case 4: /* Dual multiply subtract. */ + if (op) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + /* This addition cannot overflow. */ + if (insn & (1 << 22)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + if (rs != 15) + { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 3: /* 32 * 16 -> 32msb */ + if (op) + tcg_gen_sari_i32(tmp2, tmp2, 16); + else + gen_sxth(tmp2); + tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp64, tmp64, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if (rs != 15) + { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 5: case 6: /* 32 * 32 -> 32msb */ + gen_imull(tmp, tmp2); + if (insn & (1 << 5)) { + gen_roundqd(tmp, tmp2); + dead_tmp(tmp2); + } else { + dead_tmp(tmp); + tmp = tmp2; + } + if (rs != 15) { + tmp2 = load_reg(s, rs); + if (insn & (1 << 21)) { + tcg_gen_add_i32(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + dead_tmp(tmp2); + } + break; + case 7: /* Unsigned sum of absolute differences. */ + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + } + store_reg(s, rd, tmp); + break; + case 6: case 7: /* 64-bit multiply, Divide. */ + op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if ((op & 0x50) == 0x10) { + /* sdiv, udiv */ + if (!arm_feature(env, ARM_FEATURE_DIV)) + goto illegal_op; + if (op & 0x20) + gen_helper_udiv(tmp, tmp, tmp2); + else + gen_helper_sdiv(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((op & 0xe) == 0xc) { + /* Dual multiply accumulate long. */ + if (op & 1) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + if (op & 0x10) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + /* BUGFIX */ + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rs, rd); + gen_storeq_reg(s, rs, rd, tmp64); + tcg_temp_free_i64(tmp64); + } else { + if (op & 0x20) { + /* Unsigned 64-bit multiply */ + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + } else { + if (op & 8) { + /* smlalxy */ + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + } else { + /* Signed 64-bit multiply */ + tmp64 = gen_muls_i64_i32(tmp, tmp2); + } + } + if (op & 4) { + /* umaal */ + gen_addq_lo(s, tmp64, rs); + gen_addq_lo(s, tmp64, rd); + } else if (op & 0x40) { + /* 64-bit accumulate. */ + gen_addq(s, tmp64, rs, rd); + } + gen_storeq_reg(s, rs, rd, tmp64); + tcg_temp_free_i64(tmp64); + } + break; + } + break; + case 6: case 7: case 14: case 15: + /* Coprocessor. */ + if (((insn >> 24) & 3) == 3) { + /* Translate into the equivalent ARM encoding. */ + insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4); + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + } else { + if (insn & (1 << 28)) + goto illegal_op; + if (disas_coproc_insn (env, s, insn)) + goto illegal_op; + } + break; + case 8: case 9: case 10: case 11: + if (insn & (1 << 15)) { + /* Branches, misc control. */ + if (insn & 0x5000) { + /* Unconditional branch. */ + /* signextend(hw1[10:0]) -> offset[:12]. */ + offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff; + /* hw1[10:0] -> offset[11:1]. */ + offset |= (insn & 0x7ff) << 1; + /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22] + offset[24:22] already have the same value because of the + sign extension above. */ + offset ^= ((~insn) & (1 << 13)) << 10; + offset ^= ((~insn) & (1 << 11)) << 11; + + if (insn & (1 << 14)) { + /* Branch and link. */ + tcg_gen_movi_i32(cpu_R[14], s->pc | 1); + } + + offset += s->pc; + if (insn & (1 << 12)) { + /* b/bl */ + gen_jmp(s, offset); + } else { + /* blx */ + offset &= ~(uint32_t)2; + gen_bx_im(s, offset); + } + } else if (((insn >> 23) & 7) == 7) { + /* Misc control */ + if (insn & (1 << 13)) + goto illegal_op; + + if (insn & (1 << 26)) { + /* Secure monitor call (v6Z) */ + goto illegal_op; /* not implemented. */ + } else { + op = (insn >> 20) & 7; + switch (op) { + case 0: /* msr cpsr. */ + if (IS_M(env)) { + tmp = load_reg(s, rn); + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + dead_tmp(tmp); + gen_lookup_tb(s); + break; + } + /* fall through */ + case 1: /* msr spsr. */ + if (IS_M(env)) + goto illegal_op; + tmp = load_reg(s, rn); + if (gen_set_psr(s, + msr_mask(env, s, (insn >> 8) & 0xf, op == 1), + op == 1, tmp)) + goto illegal_op; + break; + case 2: /* cps, nop-hint. */ + if (((insn >> 8) & 7) == 0) { + gen_nop_hint(s, insn & 0xff); + } + /* Implemented as NOP in user mode. */ + if (IS_USER(s)) + break; + offset = 0; + imm = 0; + if (insn & (1 << 10)) { + if (insn & (1 << 7)) + offset |= CPSR_A; + if (insn & (1 << 6)) + offset |= CPSR_I; + if (insn & (1 << 5)) + offset |= CPSR_F; + if (insn & (1 << 9)) + imm = CPSR_A | CPSR_I | CPSR_F; + } + if (insn & (1 << 8)) { + offset |= 0x1f; + imm |= (insn & 0x1f); + } + if (offset) { + gen_set_psr_im(s, offset, 0, imm); + } + break; + case 3: /* Special control operations. */ + ARCH(7); + op = (insn >> 4) & 0xf; + switch (op) { + case 2: /* clrex */ + gen_clrex(s); + break; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + /* These execute as NOPs. */ + break; + default: + goto illegal_op; + } + break; + case 4: /* bxj */ + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, rn); + gen_bx(s, tmp); + break; + case 5: /* Exception return. */ + /* Unpredictable in user mode. */ + goto illegal_op; + case 6: /* mrs cpsr. */ + tmp = new_tmp(); + if (IS_M(env)) { + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_mrs(tmp, cpu_env, addr); + tcg_temp_free_i32(addr); + } else { + gen_helper_cpsr_read(tmp); + } + store_reg(s, rd, tmp); + break; + case 7: /* mrs spsr. */ + /* Not accessible in user mode. */ + if (IS_USER(s) || IS_M(env)) + goto illegal_op; + tmp = load_cpu_field(spsr); + store_reg(s, rd, tmp); + break; + } + } + } else { + /* Conditional branch. */ + op = (insn >> 22) & 0xf; + /* Generate a conditional jump to next instruction. */ + s->condlabel = gen_new_label(); + gen_test_cc(op ^ 1, s->condlabel); + s->condjmp = 1; + + /* offset[11:1] = insn[10:0] */ + offset = (insn & 0x7ff) << 1; + /* offset[17:12] = insn[21:16]. */ + offset |= (insn & 0x003f0000) >> 4; + /* offset[31:20] = insn[26]. */ + offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11; + /* offset[18] = insn[13]. */ + offset |= (insn & (1 << 13)) << 5; + /* offset[19] = insn[11]. */ + offset |= (insn & (1 << 11)) << 8; + + /* jump to the offset */ + gen_jmp(s, s->pc + offset); + } + } else { + /* Data processing immediate. */ + if (insn & (1 << 25)) { + if (insn & (1 << 24)) { + if (insn & (1 << 20)) + goto illegal_op; + /* Bitfield/Saturate. */ + op = (insn >> 21) & 7; + imm = insn & 0x1f; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + switch (op) { + case 2: /* Signed bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_sbfx(tmp, shift, imm); + break; + case 6: /* Unsigned bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_ubfx(tmp, shift, (1u << imm) - 1); + break; + case 3: /* Bitfield insert/clear. */ + if (imm < shift) + goto illegal_op; + imm = imm + 1 - shift; + if (imm != 32) { + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1); + dead_tmp(tmp2); + } + break; + case 7: + goto illegal_op; + default: /* Saturate. */ + if (shift) { + if (op & 1) + tcg_gen_sari_i32(tmp, tmp, shift); + else + tcg_gen_shli_i32(tmp, tmp, shift); + } + tmp2 = tcg_const_i32(imm); + if (op & 4) { + /* Unsigned. */ + if ((op & 1) && shift == 0) + gen_helper_usat16(tmp, tmp, tmp2); + else + gen_helper_usat(tmp, tmp, tmp2); + } else { + /* Signed. */ + if ((op & 1) && shift == 0) + gen_helper_ssat16(tmp, tmp, tmp2); + else + gen_helper_ssat(tmp, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + break; + } + store_reg(s, rd, tmp); + } else { + imm = ((insn & 0x04000000) >> 15) + | ((insn & 0x7000) >> 4) | (insn & 0xff); + if (insn & (1 << 22)) { + /* 16-bit immediate. */ + imm |= (insn >> 4) & 0xf000; + if (insn & (1 << 23)) { + /* movt */ + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, imm << 16); + } else { + /* movw */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, imm); + } + } else { + /* Add/sub 12-bit immediate. */ + if (rn == 15) { + offset = s->pc & ~(uint32_t)3; + if (insn & (1 << 23)) + offset -= imm; + else + offset += imm; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, offset); + } else { + tmp = load_reg(s, rn); + if (insn & (1 << 23)) + tcg_gen_subi_i32(tmp, tmp, imm); + else + tcg_gen_addi_i32(tmp, tmp, imm); + } + } + store_reg(s, rd, tmp); + } + } else { + int shifter_out = 0; + /* modified 12-bit immediate. */ + shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12); + imm = (insn & 0xff); + switch (shift) { + case 0: /* XY */ + /* Nothing to do. */ + break; + case 1: /* 00XY00XY */ + imm |= imm << 16; + break; + case 2: /* XY00XY00 */ + imm |= imm << 16; + imm <<= 8; + break; + case 3: /* XYXYXYXY */ + imm |= imm << 16; + imm |= imm << 8; + break; + default: /* Rotated constant. */ + shift = (shift << 1) | (imm >> 7); + imm |= 0x80; + imm = imm << (32 - shift); + shifter_out = 1; + break; + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, imm); + rn = (insn >> 16) & 0xf; + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + op = (insn >> 21) & 0xf; + if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0, + shifter_out, tmp, tmp2)) + goto illegal_op; + dead_tmp(tmp2); + rd = (insn >> 8) & 0xf; + if (rd != 15) { + store_reg(s, rd, tmp); + } else { + dead_tmp(tmp); + } + } + } + break; + case 12: /* Load/store single data item. */ + { + int postinc = 0; + int writeback = 0; + int user; + if ((insn & 0x01100000) == 0x01000000) { + if (disas_neon_ls_insn(env, s, insn)) + goto illegal_op; + break; + } + user = IS_USER(s); + if (rn == 15) { + addr = new_tmp(); + /* PC relative. */ + /* s->pc has already been incremented by 4. */ + imm = s->pc & 0xfffffffc; + if (insn & (1 << 23)) + imm += insn & 0xfff; + else + imm -= insn & 0xfff; + tcg_gen_movi_i32(addr, imm); + } else { + addr = load_reg(s, rn); + if (insn & (1 << 23)) { + /* Positive offset. */ + imm = insn & 0xfff; + tcg_gen_addi_i32(addr, addr, imm); + } else { + op = (insn >> 8) & 7; + imm = insn & 0xff; + switch (op) { + case 0: case 8: /* Shifted Register. */ + shift = (insn >> 4) & 0xf; + if (shift > 3) + goto illegal_op; + tmp = load_reg(s, rm); + if (shift) + tcg_gen_shli_i32(tmp, tmp, shift); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + break; + case 4: /* Negative offset. */ + tcg_gen_addi_i32(addr, addr, -imm); + break; + case 6: /* User privilege. */ + tcg_gen_addi_i32(addr, addr, imm); + user = 1; + break; + case 1: /* Post-decrement. */ + imm = -imm; + /* Fall through. */ + case 3: /* Post-increment. */ + postinc = 1; + writeback = 1; + break; + case 5: /* Pre-decrement. */ + imm = -imm; + /* Fall through. */ + case 7: /* Pre-increment. */ + tcg_gen_addi_i32(addr, addr, imm); + writeback = 1; + break; + default: + goto illegal_op; + } + } + } + op = ((insn >> 21) & 3) | ((insn >> 22) & 4); + if (insn & (1 << 20)) { + /* Load. */ + if (rs == 15 && op != 2) { + if (op & 2) + goto illegal_op; + /* Memory hint. Implemented as NOP. */ + } else { + switch (op) { + case 0: tmp = gen_ld8u(addr, user); break; + case 4: tmp = gen_ld8s(addr, user); break; + case 1: tmp = gen_ld16u(addr, user); break; + case 5: tmp = gen_ld16s(addr, user); break; + case 2: tmp = gen_ld32(addr, user); break; + default: goto illegal_op; + } + if (rs == 15) { + gen_bx(s, tmp); + } else { + store_reg(s, rs, tmp); + } + } + } else { + /* Store. */ + if (rs == 15) + goto illegal_op; + tmp = load_reg(s, rs); + switch (op) { + case 0: gen_st8(tmp, addr, user); break; + case 1: gen_st16(tmp, addr, user); break; + case 2: gen_st32(tmp, addr, user); break; + default: goto illegal_op; + } + } + if (postinc) + tcg_gen_addi_i32(addr, addr, imm); + if (writeback) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + break; + default: + goto illegal_op; + } + return 0; +illegal_op: + return 1; +} + +static void disas_thumb_insn(CPUState *env, DisasContext *s) +{ + uint32_t val, insn, op, rm, rn, rd, shift, cond; + int32_t offset; + int i; + TCGv tmp; + TCGv tmp2; + TCGv addr; + + if (s->condexec_mask) { + cond = s->condexec_cond; + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + } + + insn = lduw_code(s->pc); + s->pc += 2; + + switch (insn >> 12) { + case 0: case 1: + + rd = insn & 7; + op = (insn >> 11) & 3; + if (op == 3) { + /* add/subtract */ + rn = (insn >> 3) & 7; + tmp = load_reg(s, rn); + if (insn & (1 << 10)) { + /* immediate */ + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, (insn >> 6) & 7); + } else { + /* reg */ + rm = (insn >> 6) & 7; + tmp2 = load_reg(s, rm); + } + if (insn & (1 << 9)) { + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else { + /* shift immediate */ + rm = (insn >> 3) & 7; + shift = (insn >> 6) & 0x1f; + tmp = load_reg(s, rm); + gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0); + if (!s->condexec_mask) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + } + break; + case 2: case 3: + /* arithmetic large immediate */ + op = (insn >> 11) & 3; + rd = (insn >> 8) & 0x7; + if (op == 0) { /* mov */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, insn & 0xff); + if (!s->condexec_mask) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + } else { + tmp = load_reg(s, rd); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, insn & 0xff); + switch (op) { + case 1: /* cmp */ + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp); + dead_tmp(tmp2); + break; + case 2: /* add */ + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else + gen_helper_add_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 3: /* sub */ + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + } + } + break; + case 4: + if (insn & (1 << 11)) { + rd = (insn >> 8) & 7; + /* load pc-relative. Bit 1 of PC is ignored. */ + val = s->pc + 2 + ((insn & 0xff) * 4); + val &= ~(uint32_t)2; + addr = new_tmp(); + tcg_gen_movi_i32(addr, val); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(addr); + store_reg(s, rd, tmp); + break; + } + if (insn & (1 << 10)) { + /* data processing extended or blx */ + rd = (insn & 7) | ((insn >> 4) & 8); + rm = (insn >> 3) & 0xf; + op = (insn >> 8) & 3; + switch (op) { + case 0: /* add */ + tmp = load_reg(s, rd); + tmp2 = load_reg(s, rm); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 1: /* cmp */ + tmp = load_reg(s, rd); + tmp2 = load_reg(s, rm); + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 2: /* mov/cpy */ + tmp = load_reg(s, rm); + store_reg(s, rd, tmp); + break; + case 3:/* branch [and link] exchange thumb register */ + tmp = load_reg(s, rm); + if (insn & (1 << 7)) { + val = (uint32_t)s->pc | 1; + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + store_reg(s, 14, tmp2); + } + gen_bx(s, tmp); + break; + } + break; + } + + /* data processing register */ + rd = insn & 7; + rm = (insn >> 3) & 7; + op = (insn >> 6) & 0xf; + if (op == 2 || op == 3 || op == 4 || op == 7) { + /* the shift/rotate ops want the operands backwards */ + val = rm; + rm = rd; + rd = val; + val = 1; + } else { + val = 0; + } + + if (op == 9) { /* neg */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else if (op != 0xf) { /* mvn doesn't read its first operand */ + tmp = load_reg(s, rd); + } else { + TCGV_UNUSED(tmp); + } + + tmp2 = load_reg(s, rm); + switch (op) { + case 0x0: /* and */ + tcg_gen_and_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0x1: /* eor */ + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0x2: /* lsl */ + if (s->condexec_mask) { + gen_helper_shl(tmp2, tmp2, tmp); + } else { + gen_helper_shl_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x3: /* lsr */ + if (s->condexec_mask) { + gen_helper_shr(tmp2, tmp2, tmp); + } else { + gen_helper_shr_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x4: /* asr */ + if (s->condexec_mask) { + gen_helper_sar(tmp2, tmp2, tmp); + } else { + gen_helper_sar_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x5: /* adc */ + if (s->condexec_mask) + gen_adc(tmp, tmp2); + else + gen_helper_adc_cc(tmp, tmp, tmp2); + break; + case 0x6: /* sbc */ + if (s->condexec_mask) + gen_sub_carry(tmp, tmp, tmp2); + else + gen_helper_sbc_cc(tmp, tmp, tmp2); + break; + case 0x7: /* ror */ + if (s->condexec_mask) { + tcg_gen_andi_i32(tmp, tmp, 0x1f); + tcg_gen_rotr_i32(tmp2, tmp2, tmp); + } else { + gen_helper_ror_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x8: /* tst */ + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + rd = 16; + break; + case 0x9: /* neg */ + if (s->condexec_mask) + tcg_gen_neg_i32(tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + break; + case 0xa: /* cmp */ + gen_helper_sub_cc(tmp, tmp, tmp2); + rd = 16; + break; + case 0xb: /* cmn */ + gen_helper_add_cc(tmp, tmp, tmp2); + rd = 16; + break; + case 0xc: /* orr */ + tcg_gen_or_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xd: /* mul */ + tcg_gen_mul_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xe: /* bic */ + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xf: /* mvn */ + tcg_gen_not_i32(tmp2, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp2); + val = 1; + rm = rd; + break; + } + if (rd != 16) { + if (val) { + store_reg(s, rm, tmp2); + if (op != 0xf) + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + dead_tmp(tmp2); + } + } else { + dead_tmp(tmp); + dead_tmp(tmp2); + } + break; + + case 5: + /* load/store register offset. */ + rd = insn & 7; + rn = (insn >> 3) & 7; + rm = (insn >> 6) & 7; + op = (insn >> 9) & 7; + addr = load_reg(s, rn); + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + + if (op < 3) /* store */ + tmp = load_reg(s, rd); + + switch (op) { + case 0: /* str */ + gen_st32(tmp, addr, IS_USER(s)); + break; + case 1: /* strh */ + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: /* strb */ + gen_st8(tmp, addr, IS_USER(s)); + break; + case 3: /* ldrsb */ + tmp = gen_ld8s(addr, IS_USER(s)); + break; + case 4: /* ldr */ + tmp = gen_ld32(addr, IS_USER(s)); + break; + case 5: /* ldrh */ + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 6: /* ldrb */ + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 7: /* ldrsh */ + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + if (op >= 3) /* load */ + store_reg(s, rd, tmp); + dead_tmp(addr); + break; + + case 6: + /* load/store word immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 4) & 0x7c; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 7: + /* load/store byte immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 6) & 0x1f; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld8u(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st8(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 8: + /* load/store halfword immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 5) & 0x3e; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld16u(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 9: + /* load/store from stack */ + rd = (insn >> 8) & 7; + addr = load_reg(s, 13); + val = (insn & 0xff) * 4; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 10: + /* add to high reg */ + rd = (insn >> 8) & 7; + if (insn & (1 << 11)) { + /* SP */ + tmp = load_reg(s, 13); + } else { + /* PC. bit 1 is ignored. */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2); + } + val = (insn & 0xff) * 4; + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, rd, tmp); + break; + + case 11: + /* misc */ + op = (insn >> 8) & 0xf; + switch (op) { + case 0: + /* adjust stack pointer */ + tmp = load_reg(s, 13); + val = (insn & 0x7f) * 4; + if (insn & (1 << 7)) + val = -(int32_t)val; + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, 13, tmp); + break; + + case 2: /* sign/zero extend. */ + ARCH(6); + rd = insn & 7; + rm = (insn >> 3) & 7; + tmp = load_reg(s, rm); + switch ((insn >> 6) & 3) { + case 0: gen_sxth(tmp); break; + case 1: gen_sxtb(tmp); break; + case 2: gen_uxth(tmp); break; + case 3: gen_uxtb(tmp); break; + } + store_reg(s, rd, tmp); + break; + case 4: case 5: case 0xc: case 0xd: + /* push/pop */ + addr = load_reg(s, 13); + if (insn & (1 << 8)) + offset = 4; + else + offset = 0; + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) + offset += 4; + } + if ((insn & (1 << 11)) == 0) { + tcg_gen_addi_i32(addr, addr, -offset); + } + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + if (insn & (1 << 11)) { + /* pop */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); + } else { + /* push */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + /* advance to the next address. */ + tcg_gen_addi_i32(addr, addr, 4); + } + } + TCGV_UNUSED(tmp); + if (insn & (1 << 8)) { + if (insn & (1 << 11)) { + /* pop pc */ + tmp = gen_ld32(addr, IS_USER(s)); + /* don't set the pc until the rest of the instruction + has completed */ + } else { + /* push lr */ + tmp = load_reg(s, 14); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, 4); + } + if ((insn & (1 << 11)) == 0) { + tcg_gen_addi_i32(addr, addr, -offset); + } + /* write back the new stack pointer */ + store_reg(s, 13, addr); + /* set the new PC value */ + if ((insn & 0x0900) == 0x0900) + gen_bx(s, tmp); + break; + + case 1: case 3: case 9: case 11: /* czb */ + rm = insn & 7; + tmp = load_reg(s, rm); + s->condlabel = gen_new_label(); + s->condjmp = 1; + if (insn & (1 << 11)) + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel); + else + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel); + dead_tmp(tmp); + offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; + val = (uint32_t)s->pc + 2; + val += offset; + gen_jmp(s, val); + break; + + case 15: /* IT, nop-hint. */ + if ((insn & 0xf) == 0) { + gen_nop_hint(s, (insn >> 4) & 0xf); + break; + } + /* If Then. */ + s->condexec_cond = (insn >> 4) & 0xe; + s->condexec_mask = insn & 0x1f; + /* No actual code generated for this insn, just setup state. */ + break; + + case 0xe: /* bkpt */ + gen_set_condexec(s); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_BKPT); + s->is_jmp = DISAS_JUMP; + break; + + case 0xa: /* rev */ + ARCH(6); + rn = (insn >> 3) & 0x7; + rd = insn & 0x7; + tmp = load_reg(s, rn); + switch ((insn >> 6) & 3) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_rev16(tmp); break; + case 3: gen_revsh(tmp); break; + default: goto illegal_op; + } + store_reg(s, rd, tmp); + break; + + case 6: /* cps */ + ARCH(6); + if (IS_USER(s)) + break; + if (IS_M(env)) { + tmp = tcg_const_i32((insn & (1 << 4)) != 0); + /* PRIMASK */ + if (insn & 1) { + addr = tcg_const_i32(16); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + /* FAULTMASK */ + if (insn & 2) { + addr = tcg_const_i32(17); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + tcg_temp_free_i32(tmp); + gen_lookup_tb(s); + } else { + if (insn & (1 << 4)) + shift = CPSR_A | CPSR_I | CPSR_F; + else + shift = 0; + gen_set_psr_im(s, shift, 0, ((insn & 7) << 6) & shift); + } + break; + + default: + goto undef; + } + break; + + case 12: + /* load/store multiple */ + rn = (insn >> 8) & 0x7; + addr = load_reg(s, rn); + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); + } else { + /* store */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + /* advance to the next address */ + tcg_gen_addi_i32(addr, addr, 4); + } + } + /* Base register writeback. */ + if ((insn & (1 << rn)) == 0) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + break; + + case 13: + /* conditional branch or swi */ + cond = (insn >> 8) & 0xf; + if (cond == 0xe) + goto undef; + + if (cond == 0xf) { + /* swi */ + gen_set_condexec(s); + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SWI; + break; + } + /* generate a conditional jump to next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + + /* jump to the offset */ + val = (uint32_t)s->pc + 2; + offset = ((int32_t)insn << 24) >> 24; + val += offset << 1; + gen_jmp(s, val); + break; + + case 14: + if (insn & (1 << 11)) { + if (disas_thumb2_insn(env, s, insn)) + goto undef32; + break; + } + /* unconditional branch */ + val = (uint32_t)s->pc; + offset = ((int32_t)insn << 21) >> 21; + val += (offset << 1) + 2; + gen_jmp(s, val); + break; + + case 15: + if (disas_thumb2_insn(env, s, insn)) + goto undef32; + break; + } + return; +undef32: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; + return; +illegal_op: +undef: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; + uint16_t *gen_opc_end; + int j, lj; + target_ulong pc_start; + uint32_t next_page_start; + int num_insns; + int max_insns; + + /* generate intermediate code */ + num_temps = 0; + + pc_start = tb->pc; + + dc->tb = tb; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->condjmp = 0; + dc->thumb = env->thumb; + dc->condexec_mask = (env->condexec_bits & 0xf) << 1; + dc->condexec_cond = env->condexec_bits >> 4; +#if !defined(CONFIG_USER_ONLY) + if (IS_M(env)) { + dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1)); + } else { + dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; + } +#endif + cpu_F0s = tcg_temp_new_i32(); + cpu_F1s = tcg_temp_new_i32(); + cpu_F0d = tcg_temp_new_i64(); + cpu_F1d = tcg_temp_new_i64(); + cpu_V0 = cpu_F0d; + cpu_V1 = cpu_F1d; + /* FIXME: cpu_M0 can probably be the same as cpu_V0. */ + cpu_M0 = tcg_temp_new_i64(); + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); + /* Reset the conditional execution bits immediately. This avoids + complications trying to do it at the end of the block. */ + if (env->condexec_bits) + { + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + store_cpu_field(tmp, condexec_bits); + } + do { +#ifdef CONFIG_USER_ONLY + /* Intercept jump to the magic kernel page. */ + if (dc->pc >= 0xffff0000) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_KERNEL_TRAP); + dc->is_jmp = DISAS_UPDATE; + break; + } +#else + if (dc->pc >= 0xfffffff0 && IS_M(env)) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_EXCEPTION_EXIT); + dc->is_jmp = DISAS_UPDATE; + break; + } +#endif + + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + gen_set_condexec(dc); + gen_set_pc_im(dc->pc); + gen_exception(EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; + goto done_generating; + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + + if (env->thumb) { + disas_thumb_insn(env, dc); + if (dc->condexec_mask) { + dc->condexec_cond = (dc->condexec_cond & 0xe) + | ((dc->condexec_mask >> 4) & 1); + dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f; + if (dc->condexec_mask == 0) { + dc->condexec_cond = 0; + } + } + } else { + disas_arm_insn(env, dc); + } + if (num_temps) { + fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); + num_temps = 0; + } + + if (dc->condjmp && !dc->is_jmp) { + gen_set_label(dc->condlabel); + dc->condjmp = 0; + } + /* Translation stops when a conditional branch is encountered. + * Otherwise the subsequent code could get translated several times. + * Also stop translation when a page boundary is reached. This + * ensures prefetch aborts occur at the right place. */ + num_insns ++; + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && + !singlestep && + dc->pc < next_page_start && + num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + if (dc->condjmp) { + /* FIXME: This can theoretically happen with self-modifying + code. */ + cpu_abort(env, "IO on conditional branch instruction"); + } + gen_io_end(); + } + + /* At this stage dc->condjmp will only be set when the skipped + instruction was a conditional branch or trap, and the PC has + already been written. */ + if (unlikely(env->singlestep_enabled)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (dc->condjmp) { + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI) { + gen_exception(EXCP_SWI); + } else { + gen_exception(EXCP_DEBUG); + } + gen_set_label(dc->condlabel); + } + if (dc->condjmp || !dc->is_jmp) { + gen_set_pc_im(dc->pc); + dc->condjmp = 0; + } + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { + gen_exception(EXCP_SWI); + } else { + /* FIXME: Single stepping a WFI insn will not halt + the CPU. */ + gen_exception(EXCP_DEBUG); + } + } else { + /* While branches must always occur at the end of an IT block, + there are a few other things that can cause us to terminate + the TB in the middel of an IT block: + - Exception generating instructions (bkpt, swi, undefined). + - Page boundaries. + - Hardware watchpoints. + Hardware breakpoints have already been handled and skip this code. + */ + gen_set_condexec(dc); + switch(dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + case DISAS_WFI: + gen_helper_wfi(); + break; + case DISAS_SWI: + gen_exception(EXCP_SWI); + break; + } + if (dc->condjmp) { + gen_set_label(dc->condlabel); + gen_set_condexec(dc); + gen_goto_tb(dc, 1, dc->pc); + dc->condjmp = 0; + } + } + +done_generating: + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("----------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, dc->pc - pc_start, env->thumb); + qemu_log("\n"); + } +#endif + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } +} + +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +static const char *cpu_mode_names[16] = { + "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", + "???", "???", "???", "und", "???", "???", "???", "sys" +}; + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; +#if 0 + union { + uint32_t i; + float s; + } s0, s1; + CPU_DoubleU d; + /* ??? This assumes float64 and double have the same layout. + Oh well, it's only debug dumps. */ + union { + float64 f64; + double d; + } d0; +#endif + uint32_t psr; + + for(i=0;i<16;i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } + psr = cpsr_read(env); + cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + psr & CPSR_T ? 'T' : 'A', + cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); + +#if 0 + for (i = 0; i < 16; i++) { + d.d = env->vfp.regs[i]; + s0.i = d.l.lower; + s1.i = d.l.upper; + d0.f64 = d.d; + cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s, + i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, + d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); +#endif +} + +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->regs[15] = gen_opc_pc[pc_pos]; +} diff --git a/qemu/qemu-git/target-arm/cpu.h b/qemu/qemu-git/target-arm/cpu.h new file mode 100644 index 0000000..a75a5be --- /dev/null +++ b/qemu/qemu-git/target-arm/cpu.h @@ -0,0 +1,457 @@ +/* + * ARM virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef CPU_ARM_H +#define CPU_ARM_H + +#define TARGET_LONG_BITS 32 + +#define ELF_MACHINE EM_ARM + +#define CPUState struct CPUARMState + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define TARGET_HAS_ICE 1 + +#define EXCP_UDEF 1 /* undefined instruction */ +#define EXCP_SWI 2 /* software interrupt */ +#define EXCP_PREFETCH_ABORT 3 +#define EXCP_DATA_ABORT 4 +#define EXCP_IRQ 5 +#define EXCP_FIQ 6 +#define EXCP_BKPT 7 +#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ +#define EXCP_STREX 10 + +#define ARMV7M_EXCP_RESET 1 +#define ARMV7M_EXCP_NMI 2 +#define ARMV7M_EXCP_HARD 3 +#define ARMV7M_EXCP_MEM 4 +#define ARMV7M_EXCP_BUS 5 +#define ARMV7M_EXCP_USAGE 6 +#define ARMV7M_EXCP_SVC 11 +#define ARMV7M_EXCP_DEBUG 12 +#define ARMV7M_EXCP_PENDSV 14 +#define ARMV7M_EXCP_SYSTICK 15 + +typedef void ARMWriteCPFunc(void *opaque, int cp_info, + int srcreg, int operand, uint32_t value); +typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, + int dstreg, int operand); + +struct arm_boot_info; + +#define NB_MMU_MODES 2 + +/* We currently assume float and double are IEEE single and double + precision respectively. + Doing runtime conversions is tricky because VFP registers may contain + integer values (eg. as the result of a FTOSI instruction). + s<2n> maps to the least significant half of d + s<2n+1> maps to the most significant half of d + */ + +typedef struct CPUARMState { + /* Regs for current mode. */ + uint32_t regs[16]; + /* Frequently accessed CPSR bits are stored separately for efficiently. + This contains all the other bits. Use cpsr_{read,write} to access + the whole CPSR. */ + uint32_t uncached_cpsr; + uint32_t spsr; + + /* Banked registers. */ + uint32_t banked_spsr[6]; + uint32_t banked_r13[6]; + uint32_t banked_r14[6]; + + /* These hold r8-r12. */ + uint32_t usr_regs[5]; + uint32_t fiq_regs[5]; + + /* cpsr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NF; /* N is bit 31. All other bits are undefined. */ + uint32_t ZF; /* Z set if zero. */ + uint32_t QF; /* 0 or 1 */ + uint32_t GE; /* cpsr[19:16] */ + uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */ + uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */ + + /* System control coprocessor (cp15) */ + struct { + uint32_t c0_cpuid; + uint32_t c0_cachetype; + uint32_t c0_ccsid[16]; /* Cache size. */ + uint32_t c0_clid; /* Cache level. */ + uint32_t c0_cssel; /* Cache size selection. */ + uint32_t c0_c1[8]; /* Feature registers. */ + uint32_t c0_c2[8]; /* Instruction set registers. */ + uint32_t c1_sys; /* System control register. */ + uint32_t c1_coproc; /* Coprocessor access register. */ + uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ + uint32_t c2_base0; /* MMU translation table base 0. */ + uint32_t c2_base1; /* MMU translation table base 1. */ + uint32_t c2_control; /* MMU translation table base control. */ + uint32_t c2_mask; /* MMU translation table base selection mask. */ + uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ + uint32_t c2_data; /* MPU data cachable bits. */ + uint32_t c2_insn; /* MPU instruction cachable bits. */ + uint32_t c3; /* MMU domain access control register + MPU write buffer control. */ + uint32_t c5_insn; /* Fault status registers. */ + uint32_t c5_data; + uint32_t c6_region[8]; /* MPU base/size registers. */ + uint32_t c6_insn; /* Fault address registers. */ + uint32_t c6_data; + uint32_t c9_insn; /* Cache lockdown registers. */ + uint32_t c9_data; + uint32_t c13_fcse; /* FCSE PID. */ + uint32_t c13_context; /* Context ID. */ + uint32_t c13_tls1; /* User RW Thread register. */ + uint32_t c13_tls2; /* User RO Thread register. */ + uint32_t c13_tls3; /* Privileged Thread register. */ + uint32_t c15_cpar; /* XScale Coprocessor Access Register */ + uint32_t c15_ticonfig; /* TI925T configuration byte. */ + uint32_t c15_i_max; /* Maximum D-cache dirty line index. */ + uint32_t c15_i_min; /* Minimum D-cache dirty line index. */ + uint32_t c15_threadid; /* TI debugger thread-ID. */ + } cp15; + + struct { + uint32_t other_sp; + uint32_t vecbase; + uint32_t basepri; + uint32_t control; + int current_sp; + int exception; + int pending_exception; + void *nvic; + } v7m; + + /* Coprocessor IO used by peripherals */ + struct { + ARMReadCPFunc *cp_read; + ARMWriteCPFunc *cp_write; + void *opaque; + } cp[15]; + + /* Thumb-2 EE state. */ + uint32_t teecr; + uint32_t teehbr; + + /* Internal CPU feature flags. */ + uint32_t features; + + /* Callback for vectored interrupt controller. */ + int (*get_irq_vector)(struct CPUARMState *); + void *irq_opaque; + + /* VFP coprocessor state. */ + struct { + float64 regs[32]; + + uint32_t xregs[16]; + /* We store these fpcsr fields separately for convenience. */ + int vec_len; + int vec_stride; + + /* scratch space when Tn are not sufficient. */ + uint32_t scratch[8]; + + float_status fp_status; + } vfp; + uint32_t exclusive_addr; + uint32_t exclusive_val; + uint32_t exclusive_high; +#if defined(CONFIG_USER_ONLY) + uint32_t exclusive_test; + uint32_t exclusive_info; +#endif + + /* iwMMXt coprocessor state. */ + struct { + uint64_t regs[16]; + uint64_t val; + + uint32_t cregs[16]; + } iwmmxt; + +#if defined(CONFIG_USER_ONLY) + /* For usermode syscall translation. */ + int eabi; +#endif + + CPU_COMMON + + /* These fields after the common ones so they are preserved on reset. */ + struct arm_boot_info *boot_info; +} CPUARMState; + +CPUARMState *cpu_arm_init(const char *cpu_model); +void arm_translate_init(void); +int cpu_arm_exec(CPUARMState *s); +void cpu_arm_close(CPUARMState *s); +void do_interrupt(CPUARMState *); +void switch_mode(CPUARMState *, int); +uint32_t do_arm_semihosting(CPUARMState *env); + +/* 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. */ +int cpu_arm_signal_handler(int host_signum, void *pinfo, + void *puc); +int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw, + int mmu_idx, int is_softmuu); +#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault + +void cpu_lock(void); +void cpu_unlock(void); +static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) +{ + env->cp15.c13_tls2 = newtls; +} + +#define CPSR_M (0x1f) +#define CPSR_T (1 << 5) +#define CPSR_F (1 << 6) +#define CPSR_I (1 << 7) +#define CPSR_A (1 << 8) +#define CPSR_E (1 << 9) +#define CPSR_IT_2_7 (0xfc00) +#define CPSR_GE (0xf << 16) +#define CPSR_RESERVED (0xf << 20) +#define CPSR_J (1 << 24) +#define CPSR_IT_0_1 (3 << 25) +#define CPSR_Q (1 << 27) +#define CPSR_V (1 << 28) +#define CPSR_C (1 << 29) +#define CPSR_Z (1 << 30) +#define CPSR_N (1 << 31) +#define CPSR_NZCV (CPSR_N | CPSR_Z | CPSR_C | CPSR_V) + +#define CPSR_IT (CPSR_IT_0_1 | CPSR_IT_2_7) +#define CACHED_CPSR_BITS (CPSR_T | CPSR_GE | CPSR_IT | CPSR_Q | CPSR_NZCV) +/* Bits writable in user mode. */ +#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE) +/* Execution state bits. MRS read as zero, MSR writes ignored. */ +#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) + +/* Return the current CPSR value. */ +uint32_t cpsr_read(CPUARMState *env); +/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask); + +/* Return the current xPSR value. */ +static inline uint32_t xpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->ZF == 0); + return (env->NF & 0x80000000) | (ZF << 30) + | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | env->v7m.exception; +} + +/* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ +static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + if (mask & CPSR_NZCV) { + env->ZF = (~val) & CPSR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & (1 << 24)) + env->thumb = ((val & (1 << 24)) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & 0x1ff) { + env->v7m.exception = val & 0x1ff; + } +} + +enum arm_cpu_mode { + ARM_CPU_MODE_USR = 0x10, + ARM_CPU_MODE_FIQ = 0x11, + ARM_CPU_MODE_IRQ = 0x12, + ARM_CPU_MODE_SVC = 0x13, + ARM_CPU_MODE_ABT = 0x17, + ARM_CPU_MODE_UND = 0x1b, + ARM_CPU_MODE_SYS = 0x1f +}; + +/* VFP system registers. */ +#define ARM_VFP_FPSID 0 +#define ARM_VFP_FPSCR 1 +#define ARM_VFP_MVFR1 6 +#define ARM_VFP_MVFR0 7 +#define ARM_VFP_FPEXC 8 +#define ARM_VFP_FPINST 9 +#define ARM_VFP_FPINST2 10 + +/* iwMMXt coprocessor control registers. */ +#define ARM_IWMMXT_wCID 0 +#define ARM_IWMMXT_wCon 1 +#define ARM_IWMMXT_wCSSF 2 +#define ARM_IWMMXT_wCASF 3 +#define ARM_IWMMXT_wCGR0 8 +#define ARM_IWMMXT_wCGR1 9 +#define ARM_IWMMXT_wCGR2 10 +#define ARM_IWMMXT_wCGR3 11 + +enum arm_features { + ARM_FEATURE_VFP, + ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ + ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ + ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ + ARM_FEATURE_V6, + ARM_FEATURE_V6K, + ARM_FEATURE_V7, + ARM_FEATURE_THUMB2, + ARM_FEATURE_MPU, /* Only has Memory Protection Unit, not full MMU. */ + ARM_FEATURE_VFP3, + ARM_FEATURE_VFP_FP16, + ARM_FEATURE_NEON, + ARM_FEATURE_DIV, + ARM_FEATURE_M, /* Microcontroller profile. */ + ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ + ARM_FEATURE_THUMB2EE +}; + +static inline int arm_feature(CPUARMState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +/* Interface between CPU and Interrupt controller. */ +void armv7m_nvic_set_pending(void *opaque, int irq); +int armv7m_nvic_acknowledge_irq(void *opaque); +void armv7m_nvic_complete_irq(void *opaque, int irq); + +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque); + +/* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3. + Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are + conventional cores (ie. Application or Realtime profile). */ + +#define IS_M(env) arm_feature(env, ARM_FEATURE_M) +#define ARM_CPUID(env) (env->cp15.c0_cpuid) + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_ARM946 0x41059461 +#define ARM_CPUID_TI915T 0x54029152 +#define ARM_CPUID_TI925T 0x54029252 +#define ARM_CPUID_PXA250 0x69052100 +#define ARM_CPUID_PXA255 0x69052d00 +#define ARM_CPUID_PXA260 0x69052903 +#define ARM_CPUID_PXA261 0x69052d05 +#define ARM_CPUID_PXA262 0x69052d06 +#define ARM_CPUID_PXA270 0x69054110 +#define ARM_CPUID_PXA270_A0 0x69054110 +#define ARM_CPUID_PXA270_A1 0x69054111 +#define ARM_CPUID_PXA270_B0 0x69054112 +#define ARM_CPUID_PXA270_B1 0x69054113 +#define ARM_CPUID_PXA270_C0 0x69054114 +#define ARM_CPUID_PXA270_C5 0x69054117 +#define ARM_CPUID_ARM1136 0x4117b363 +#define ARM_CPUID_ARM1136_R2 0x4107b362 +#define ARM_CPUID_ARM11MPCORE 0x410fb022 +#define ARM_CPUID_CORTEXA8 0x410fc080 +#define ARM_CPUID_CORTEXA9 0x410fc090 +#define ARM_CPUID_CORTEXM3 0x410fc231 +#define ARM_CPUID_ANY 0xffffffff + +#if defined(CONFIG_USER_ONLY) +#define TARGET_PAGE_BITS 12 +#else +/* The ARM MMU allows 1k pages. */ +/* ??? Linux doesn't actually use these, and they're deprecated in recent + architecture revisions. Maybe a configure option to disable them. */ +#define TARGET_PAGE_BITS 10 +#endif + +#define cpu_init cpu_arm_init +#define cpu_exec cpu_arm_exec +#define cpu_gen_code cpu_arm_gen_code +#define cpu_signal_handler cpu_arm_signal_handler +#define cpu_list arm_cpu_list + +#ifndef X49GP +#define CPU_SAVE_VERSION 2 +#endif + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0; +} + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[13] = newsp; + env->regs[0] = 0; +} +#endif + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->regs[15] = tb->pc; +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->regs[15]; + *cs_base = 0; + *flags = env->thumb | (env->vfp.vec_len << 1) + | (env->vfp.vec_stride << 4) | (env->condexec_bits << 8); + if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) + *flags |= (1 << 6); + if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) + *flags |= (1 << 7); +} + +#endif diff --git a/qemu/qemu-git/target-arm/exec.h b/qemu/qemu-git/target-arm/exec.h new file mode 100644 index 0000000..e9848e1 --- /dev/null +++ b/qemu/qemu-git/target-arm/exec.h @@ -0,0 +1,60 @@ +/* + * ARM execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "config.h" +#include "dyngen-exec.h" + +register struct CPUARMState *env asm(AREG0); + +#define M0 env->iwmmxt.val + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +static inline int cpu_has_work(CPUState *env) +{ + return (env->interrupt_request & + (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)); +} + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + /* An interrupt wakes the CPU even if the I and F CPSR bits are + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (cpu_has_work(env)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +void raise_exception(int); diff --git a/qemu/qemu-git/target-arm/helper.c b/qemu/qemu-git/target-arm/helper.c new file mode 100644 index 0000000..b3aec99 --- /dev/null +++ b/qemu/qemu-git/target-arm/helper.c @@ -0,0 +1,2598 @@ +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "helpers.h" +#include "qemu-common.h" +#include "host-utils.h" + +static uint32_t cortexa9_cp15_c0_c1[8] = +{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 }; + +static uint32_t cortexa9_cp15_c0_c2[8] = +{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 }; + +static uint32_t cortexa8_cp15_c0_c1[8] = +{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 }; + +static uint32_t cortexa8_cp15_c0_c2[8] = +{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 }; + +static uint32_t mpcore_cp15_c0_c1[8] = +{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 }; + +static uint32_t mpcore_cp15_c0_c2[8] = +{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 }; + +static uint32_t arm1136_cp15_c0_c1[8] = +{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 }; + +static uint32_t arm1136_cp15_c0_c2[8] = +{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 }; + +static uint32_t cpu_arm_find_by_name(const char *name); + +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1u << feature; +} + +static void cpu_reset_model_id(CPUARMState *env, uint32_t id) +{ + env->cp15.c0_cpuid = id; + switch (id) { + case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_VFP); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; + break; + case ARM_CPUID_ARM946: + set_feature(env, ARM_FEATURE_MPU); + env->cp15.c0_cachetype = 0x0f004006; + env->cp15.c1_sys = 0x00000078; + break; + case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; + break; + case ARM_CPUID_ARM1136_R2: + case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_ARM11MPCORE: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_CORTEXA8: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; + memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x82048004; + env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3; + env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */ + env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */ + env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */ + break; + case ARM_CPUID_CORTEXA9: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_VFP_FP16); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */ + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111; + memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x80038003; + env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3; + env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */ + env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */ + break; + case ARM_CPUID_CORTEXM3: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_M); + set_feature(env, ARM_FEATURE_DIV); + break; + case ARM_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_VFP_FP16); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_THUMB2EE); + set_feature(env, ARM_FEATURE_DIV); + break; + case ARM_CPUID_TI915T: + case ARM_CPUID_TI925T: + set_feature(env, ARM_FEATURE_OMAPCP); + env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */ + env->cp15.c0_cachetype = 0x5109149; + env->cp15.c1_sys = 0x00000070; + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + break; + case ARM_CPUID_PXA250: + case ARM_CPUID_PXA255: + case ARM_CPUID_PXA260: + case ARM_CPUID_PXA261: + case ARM_CPUID_PXA262: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; + break; + case ARM_CPUID_PXA270_A0: + case ARM_CPUID_PXA270_A1: + case ARM_CPUID_PXA270_B0: + case ARM_CPUID_PXA270_B1: + case ARM_CPUID_PXA270_C0: + case ARM_CPUID_PXA270_C5: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + set_feature(env, ARM_FEATURE_IWMMXT); + env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; + env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + break; + } +} + +void cpu_reset(CPUARMState *env) +{ + uint32_t id; + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + + id = env->cp15.c0_cpuid; + memset(env, 0, offsetof(CPUARMState, breakpoints)); + if (id) + cpu_reset_model_id(env, id); +#if defined (CONFIG_USER_ONLY) + env->uncached_cpsr = ARM_CPU_MODE_USR; + env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30; +#else + /* SVC mode with interrupts disabled. */ + env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is + clear at reset. */ + if (IS_M(env)) + env->uncached_cpsr &= ~CPSR_I; + env->vfp.xregs[ARM_VFP_FPEXC] = 0; + env->cp15.c2_base_mask = 0xffffc000u; +#endif + env->regs[15] = 0; + tlb_flush(env, 1); +} + +static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + /* VFP data registers are always little-endian. */ + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[reg]); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + /* Aliases for Q regs. */ + nregs += 16; + if (reg < nregs) { + stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]); + stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]); + return 16; + } + } + switch (reg - nregs) { + case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4; + case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4; + case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4; + } + return 0; +} + +static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg) +{ + int nregs; + + nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16; + if (reg < nregs) { + env->vfp.regs[reg] = ldfq_le_p(buf); + return 8; + } + if (arm_feature(env, ARM_FEATURE_NEON)) { + nregs += 16; + if (reg < nregs) { + env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf); + env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8); + return 16; + } + } + switch (reg - nregs) { + case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4; + case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4; + case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); return 4; + } + return 0; +} + +CPUARMState *cpu_arm_init(const char *cpu_model) +{ + CPUARMState *env; + uint32_t id; + static int inited = 0; + + id = cpu_arm_find_by_name(cpu_model); + if (id == 0) + return NULL; + env = qemu_mallocz(sizeof(CPUARMState)); + cpu_exec_init(env); + if (!inited) { + inited = 1; + arm_translate_init(); + } + + env->cpu_model_str = cpu_model; + env->cp15.c0_cpuid = id; + cpu_reset(env); + if (arm_feature(env, ARM_FEATURE_NEON)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 51, "arm-neon.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP3)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 35, "arm-vfp3.xml", 0); + } else if (arm_feature(env, ARM_FEATURE_VFP)) { + gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, + 19, "arm-vfp.xml", 0); + } + qemu_init_vcpu(env); + return env; +} + +struct arm_cpu_t { + uint32_t id; + const char *name; +}; + +static const struct arm_cpu_t arm_cpu_names[] = { + { ARM_CPUID_ARM926, "arm926"}, + { ARM_CPUID_ARM946, "arm946"}, + { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_ARM1136, "arm1136"}, + { ARM_CPUID_ARM1136_R2, "arm1136-r2"}, + { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, + { ARM_CPUID_CORTEXM3, "cortex-m3"}, + { ARM_CPUID_CORTEXA8, "cortex-a8"}, + { ARM_CPUID_CORTEXA9, "cortex-a9"}, + { ARM_CPUID_TI925T, "ti925t" }, + { ARM_CPUID_PXA250, "pxa250" }, + { ARM_CPUID_PXA255, "pxa255" }, + { ARM_CPUID_PXA260, "pxa260" }, + { ARM_CPUID_PXA261, "pxa261" }, + { ARM_CPUID_PXA262, "pxa262" }, + { ARM_CPUID_PXA270, "pxa270" }, + { ARM_CPUID_PXA270_A0, "pxa270-a0" }, + { ARM_CPUID_PXA270_A1, "pxa270-a1" }, + { ARM_CPUID_PXA270_B0, "pxa270-b0" }, + { ARM_CPUID_PXA270_B1, "pxa270-b1" }, + { ARM_CPUID_PXA270_C0, "pxa270-c0" }, + { ARM_CPUID_PXA270_C5, "pxa270-c5" }, + { ARM_CPUID_ANY, "any"}, + { 0, NULL} +}; + +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i; + + (*cpu_fprintf)(f, "Available CPUs:\n"); + for (i = 0; arm_cpu_names[i].name; i++) { + (*cpu_fprintf)(f, " %s\n", arm_cpu_names[i].name); + } +} + +/* return 0 if not found */ +static uint32_t cpu_arm_find_by_name(const char *name) +{ + int i; + uint32_t id; + + id = 0; + for (i = 0; arm_cpu_names[i].name; i++) { + if (strcmp(name, arm_cpu_names[i].name) == 0) { + id = arm_cpu_names[i].id; + break; + } + } + return id; +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + +uint32_t cpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->ZF == 0); + return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16); +} + +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + if (mask & CPSR_NZCV) { + env->ZF = (~val) & CPSR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & CPSR_T) + env->thumb = ((val & CPSR_T) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & CPSR_GE) { + env->GE = (val >> 16) & 0xf; + } + + if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { + switch_mode(env, val & CPSR_M); + } + mask &= ~CACHED_CPSR_BITS; + env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); +} + +/* Sign/zero extend */ +uint32_t HELPER(sxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(int8_t)x; + res |= (uint32_t)(int8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(uxtb16)(uint32_t x) +{ + uint32_t res; + res = (uint16_t)(uint8_t)x; + res |= (uint32_t)(uint8_t)(x >> 16) << 16; + return res; +} + +uint32_t HELPER(clz)(uint32_t x) +{ + return clz32(x); +} + +int32_t HELPER(sdiv)(int32_t num, int32_t den) +{ + if (den == 0) + return 0; + if (num == INT_MIN && den == -1) + return INT_MIN; + return num / den; +} + +uint32_t HELPER(udiv)(uint32_t num, uint32_t den) +{ + if (den == 0) + return 0; + return num / den; +} + +uint32_t HELPER(rbit)(uint32_t x) +{ + x = ((x & 0xff000000) >> 24) + | ((x & 0x00ff0000) >> 8) + | ((x & 0x0000ff00) << 8) + | ((x & 0x000000ff) << 24); + x = ((x & 0xf0f0f0f0) >> 4) + | ((x & 0x0f0f0f0f) << 4); + x = ((x & 0x88888888) >> 3) + | ((x & 0x44444444) >> 1) + | ((x & 0x22222222) << 1) + | ((x & 0x11111111) << 3); + return x; +} + +uint32_t HELPER(abs)(uint32_t x) +{ + return ((int32_t)x < 0) ? -x : x; +} + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + if (rw == 2) { + env->exception_index = EXCP_PREFETCH_ABORT; + env->cp15.c6_insn = address; + } else { + env->exception_index = EXCP_DATA_ABORT; + env->cp15.c6_data = address; + } + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return; +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return 0; +} + +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); +} + +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); + return 0; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); +} + +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); + return 0; +} + +void switch_mode(CPUState *env, int mode) +{ + if (mode != ARM_CPU_MODE_USR) + cpu_abort(env, "Tried to switch out of user mode\n"); +} + +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + cpu_abort(env, "banked r13 write\n"); +} + +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) +{ + cpu_abort(env, "banked r13 read\n"); + return 0; +} + +#else + +extern int semihosting_enabled; + +/* Map CPU modes onto saved register banks. */ +static inline int bank_number (int mode) +{ + switch (mode) { + case ARM_CPU_MODE_USR: + case ARM_CPU_MODE_SYS: + return 0; + case ARM_CPU_MODE_SVC: + return 1; + case ARM_CPU_MODE_ABT: + return 2; + case ARM_CPU_MODE_UND: + return 3; + case ARM_CPU_MODE_IRQ: + return 4; + case ARM_CPU_MODE_FIQ: + return 5; + } + cpu_abort(cpu_single_env, "Bad mode %x\n", mode); + return -1; +} + +void switch_mode(CPUState *env, int mode) +{ + int old_mode; + int i; + + old_mode = env->uncached_cpsr & CPSR_M; + if (mode == old_mode) + return; + + if (old_mode == ARM_CPU_MODE_FIQ) { + memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + } else if (mode == ARM_CPU_MODE_FIQ) { + memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + } + + i = bank_number(old_mode); + env->banked_r13[i] = env->regs[13]; + env->banked_r14[i] = env->regs[14]; + env->banked_spsr[i] = env->spsr; + + i = bank_number(mode); + env->regs[13] = env->banked_r13[i]; + env->regs[14] = env->banked_r14[i]; + env->spsr = env->banked_spsr[i]; +} + +static void v7m_push(CPUARMState *env, uint32_t val) +{ + env->regs[13] -= 4; + stl_phys(env->regs[13], val); +} + +static uint32_t v7m_pop(CPUARMState *env) +{ + uint32_t val; + val = ldl_phys(env->regs[13]); + env->regs[13] += 4; + return val; +} + +/* Switch to V7M main or process stack pointer. */ +static void switch_v7m_sp(CPUARMState *env, int process) +{ + uint32_t tmp; + if (env->v7m.current_sp != process) { + tmp = env->v7m.other_sp; + env->v7m.other_sp = env->regs[13]; + env->regs[13] = tmp; + env->v7m.current_sp = process; + } +} + +static void do_v7m_exception_exit(CPUARMState *env) +{ + uint32_t type; + uint32_t xpsr; + + type = env->regs[15]; + if (env->v7m.exception != 0) + armv7m_nvic_complete_irq(env->v7m.nvic, env->v7m.exception); + + /* Switch to the target stack. */ + switch_v7m_sp(env, (type & 4) != 0); + /* Pop registers. */ + env->regs[0] = v7m_pop(env); + env->regs[1] = v7m_pop(env); + env->regs[2] = v7m_pop(env); + env->regs[3] = v7m_pop(env); + env->regs[12] = v7m_pop(env); + env->regs[14] = v7m_pop(env); + env->regs[15] = v7m_pop(env); + xpsr = v7m_pop(env); + xpsr_write(env, xpsr, 0xfffffdff); + /* Undo stack alignment. */ + if (xpsr & 0x200) + env->regs[13] |= 4; + /* ??? The exception return type specifies Thread/Handler mode. However + this is also implied by the xPSR value. Not sure what to do + if there is a mismatch. */ + /* ??? Likewise for mismatches between the CONTROL register and the stack + pointer. */ +} + +static void do_interrupt_v7m(CPUARMState *env) +{ + uint32_t xpsr = xpsr_read(env); + uint32_t lr; + uint32_t addr; + + lr = 0xfffffff1; + if (env->v7m.current_sp) + lr |= 4; + if (env->v7m.exception == 0) + lr |= 8; + + /* For exceptions we just mark as pending on the NVIC, and let that + handle it. */ + /* TODO: Need to escalate if the current priority is higher than the + one we're raising. */ + switch (env->exception_index) { + case EXCP_UDEF: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE); + return; + case EXCP_SWI: + env->regs[15] += 2; + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC); + return; + case EXCP_PREFETCH_ABORT: + case EXCP_DATA_ABORT: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM); + return; + case EXCP_BKPT: + if (semihosting_enabled) { + int nr; + nr = lduw_code(env->regs[15]) & 0xff; + if (nr == 0xab) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); + return; + case EXCP_IRQ: + env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic); + break; + case EXCP_EXCEPTION_EXIT: + do_v7m_exception_exit(env); + return; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + + /* Align stack pointer. */ + /* ??? Should only do this if Configuration Control Register + STACKALIGN bit is set. */ + if (env->regs[13] & 4) { + env->regs[13] -= 4; + xpsr |= 0x200; + } + /* Switch to the handler mode. */ + v7m_push(env, xpsr); + v7m_push(env, env->regs[15]); + v7m_push(env, env->regs[14]); + v7m_push(env, env->regs[12]); + v7m_push(env, env->regs[3]); + v7m_push(env, env->regs[2]); + v7m_push(env, env->regs[1]); + v7m_push(env, env->regs[0]); + switch_v7m_sp(env, 0); + env->uncached_cpsr &= ~CPSR_IT; + env->regs[14] = lr; + addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4); + env->regs[15] = addr & 0xfffffffe; + env->thumb = addr & 1; +} + +/* Handle a CPU exception. */ +void do_interrupt(CPUARMState *env) +{ + uint32_t addr; + uint32_t mask; + int new_mode; + uint32_t offset; + + if (IS_M(env)) { + do_interrupt_v7m(env); + return; + } + /* TODO: Vectored interrupt controller. */ + switch (env->exception_index) { + case EXCP_UDEF: + new_mode = ARM_CPU_MODE_UND; + addr = 0x04; + mask = CPSR_I; + if (env->thumb) + offset = 2; + else + offset = 4; + break; + case EXCP_SWI: + if (semihosting_enabled) { + /* Check for semihosting interrupt. */ + if (env->thumb) { + mask = lduw_code(env->regs[15] - 2) & 0xff; + } else { + mask = ldl_code(env->regs[15] - 4) & 0xffffff; + } + /* Only intercept calls from privileged modes, to provide some + semblance of security. */ + if (((mask == 0x123456 && !env->thumb) + || (mask == 0xab && env->thumb)) + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[0] = do_arm_semihosting(env); + return; + } + } + new_mode = ARM_CPU_MODE_SVC; + addr = 0x08; + mask = CPSR_I; + /* The PC already points to the next instruction. */ + offset = 0; + break; + case EXCP_BKPT: + /* See if this is a semihosting syscall. */ + if (env->thumb && semihosting_enabled) { + mask = lduw_code(env->regs[15]) & 0xff; + if (mask == 0xab + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } + /* Fall through to prefetch abort. */ + case EXCP_PREFETCH_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x0c; + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_DATA_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + break; + case EXCP_IRQ: + new_mode = ARM_CPU_MODE_IRQ; + addr = 0x18; + /* Disable IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_FIQ: + new_mode = ARM_CPU_MODE_FIQ; + addr = 0x1c; + /* Disable FIQ, IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I | CPSR_F; + offset = 4; + break; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + /* High vectors. */ + if (env->cp15.c1_sys & (1 << 13)) { + addr += 0xffff0000; + } + switch_mode (env, new_mode); + env->spsr = cpsr_read(env); + /* Clear IT bits. */ + env->condexec_bits = 0; + /* Switch to the new mode, and switch to Arm mode. */ + /* ??? Thumb interrupt handlers not implemented. */ + env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; + env->uncached_cpsr |= mask; + env->thumb = 0; + env->regs[14] = env->regs[15] + offset; + env->regs[15] = addr; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +/* Check section/page access permissions. + Returns the page protection flags, or zero if the access is not + permitted. */ +static inline int check_ap(CPUState *env, int ap, int domain, int access_type, + int is_user) +{ + int prot_ro; + + if (domain == 3) + return PAGE_READ | PAGE_WRITE; + + if (access_type == 1) + prot_ro = 0; + else + prot_ro = PAGE_READ; + + switch (ap) { + case 0: + if (access_type == 1) + return 0; + switch ((env->cp15.c1_sys >> 8) & 3) { + case 1: + return is_user ? 0 : PAGE_READ; + case 2: + return PAGE_READ; + default: + return 0; + } + case 1: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 2: + if (is_user) + return prot_ro; + else + return PAGE_READ | PAGE_WRITE; + case 3: + return PAGE_READ | PAGE_WRITE; + case 4: /* Reserved. */ + return 0; + case 5: + return is_user ? 0 : prot_ro; + case 6: + return prot_ro; + case 7: + if (!arm_feature (env, ARM_FEATURE_V7)) + return 0; + return prot_ro; + default: + abort(); + } +} + +static uint32_t get_level1_table_address(CPUState *env, uint32_t address) +{ + uint32_t table; + + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1 & 0xffffc000; + else + table = env->cp15.c2_base0 & env->cp15.c2_base_mask; + + table |= (address >> 18) & 0x3ffc; + return table; +} + +static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + table = get_level1_table_address(env, address); + desc = ldl_phys(table); + type = (desc & 3); + domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; + if (type == 0) { + /* Section translation fault. */ + code = 5; + goto do_fault; + } + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + code = 13; + } else { + /* Lookup l2 entry. */ + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } + desc = ldl_phys(table); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 3: /* 1k page. */ + if (type == 1) { + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + } else { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + } + ap = (desc >> 4) & 3; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); + } + code = 15; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + return 0; +do_fault: + return code | (domain << 4); +} + +static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + uint32_t xn; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + table = get_level1_table_address(env, address); + desc = ldl_phys(table); + type = (desc & 3); + if (type == 0) { + /* Section translation fault. */ + code = 5; + domain = 0; + goto do_fault; + } else if (type == 2 && (desc & (1 << 18))) { + /* Supersection. */ + domain = 0; + } else { + /* Section or page. */ + domain = (desc >> 4) & 0x1e; + } + domain = (env->cp15.c3 >> domain) & 3; + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + if (desc & (1 << 18)) { + /* Supersection. */ + phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); + } else { + /* Section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + } + ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); + xn = desc & (1 << 4); + code = 13; + } else { + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + desc = ldl_phys(table); + ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + xn = desc & (1 << 15); + break; + case 2: case 3: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + xn = desc & 1; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); + } + code = 15; + } + if (xn && access_type == 2) + goto do_fault; + + /* The simplified model uses AP[0] as an access control bit. */ + if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) { + /* Access flag fault. */ + code = (code == 15) ? 6 : 3; + goto do_fault; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + return 0; +do_fault: + return code | (domain << 4); +} + +static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int n; + uint32_t mask; + uint32_t base; + + *phys_ptr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) + continue; + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) + break; + } + if (n < 0) + return 2; + + if (access_type == 2) { + mask = env->cp15.c5_insn; + } else { + mask = env->cp15.c5_data; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + return 1; + case 1: + if (is_user) + return 1; + *prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + *prot = PAGE_READ; + if (!is_user) + *prot |= PAGE_WRITE; + break; + case 3: + *prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) + return 1; + *prot = PAGE_READ; + break; + case 6: + *prot = PAGE_READ; + break; + default: + /* Bad permission. */ + return 1; + } + return 0; +} + +static inline int get_phys_addr(CPUState *env, uint32_t address, + int access_type, int is_user, + uint32_t *phys_ptr, int *prot) +{ + /* Fast Context Switch Extension. */ + if (address < 0x02000000) + address += env->cp15.c13_fcse; + + if ((env->cp15.c1_sys & 1) == 0) { + /* MMU/MPU disabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } else if (arm_feature(env, ARM_FEATURE_MPU)) { + return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, + prot); + } else if (env->cp15.c1_sys & (1 << 23)) { + return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, + prot); + } else { + return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr, + prot); + } +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, + int access_type, int mmu_idx, int is_softmmu) +{ + uint32_t phys_addr; + int prot; + int ret, is_user; + + is_user = mmu_idx == MMU_USER_IDX; + ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); + if (ret == 0) { + /* Map a single [sub]page. */ + phys_addr &= ~(uint32_t)0x3ff; + address &= ~(uint32_t)0x3ff; + return tlb_set_page (env, address, phys_addr, prot, mmu_idx, + is_softmmu); + } + + if (access_type == 2) { + env->cp15.c5_insn = ret; + env->cp15.c6_insn = address; + env->exception_index = EXCP_PREFETCH_ABORT; + } else { + env->cp15.c5_data = ret; + if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) + env->cp15.c5_data |= (1 << 11); + env->cp15.c6_data = address; + env->exception_index = EXCP_DATA_ABORT; + } + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot; + int ret; + + ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot); + + if (ret != 0) + return -1; + + return phys_addr; +} + +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int src = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_write) + env->cp[cp_num].cp_write(env->cp[cp_num].opaque, + cp_info, src, operand, val); +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int dest = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_read) + return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, + cp_info, dest, operand); + return 0; +} + +/* Return basic MPU access permission bits. */ +static uint32_t simple_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val >> i) & mask; + mask <<= 2; + } + return ret; +} + +/* Pad basic MPU access permission bits to extended format. */ +static uint32_t extended_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val & mask) << i; + mask <<= 2; + } + return ret; +} + +void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1; + int op2; + int crm; + + op1 = (insn >> 21) & 7; + op2 = (insn >> 5) & 7; + crm = insn & 0xf; + switch ((insn >> 16) & 0xf) { + case 0: + /* ID codes. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + break; + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; + if (arm_feature(env, ARM_FEATURE_V7) + && op1 == 2 && crm == 0 && op2 == 0) { + env->cp15.c0_cssel = val & 0xf; + break; + } + goto bad_reg; + case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) + env->cp15.c1_sys = val; + /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ + tlb_flush(env, 1); + break; + case 1: /* Auxiliary cotrol register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + env->cp15.c1_xscaleauxcr = val; + break; + } + /* Not implemented. */ + break; + case 2: + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; + if (env->cp15.c1_coproc != val) { + env->cp15.c1_coproc = val; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + } + break; + default: + goto bad_reg; + } + break; + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + env->cp15.c2_data = val; + break; + case 1: + env->cp15.c2_insn = val; + break; + default: + goto bad_reg; + } + } else { + switch (op2) { + case 0: + env->cp15.c2_base0 = val; + break; + case 1: + env->cp15.c2_base1 = val; + break; + case 2: + val &= 7; + env->cp15.c2_control = val; + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); + break; + default: + goto bad_reg; + } + } + break; + case 3: /* MMU Domain access control / MPU write buffer control. */ + env->cp15.c3 = val; + tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ + break; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); + env->cp15.c5_data = val; + break; + case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); + env->cp15.c5_insn = val; + break; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_data = val; + break; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_insn = val; + break; + default: + goto bad_reg; + } + break; + case 6: /* MMU Fault address / MPU base/size. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + if (crm >= 8) + goto bad_reg; + env->cp15.c6_region[crm] = val; + } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + env->cp15.c6_data = val; + break; + case 1: /* ??? This is WFAR on armv6 */ + case 2: + env->cp15.c6_insn = val; + break; + default: + goto bad_reg; + } + } + break; + case 7: /* Cache control. */ + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + /* No cache, so nothing to do. */ + /* ??? MPCore has VA to PA translation functions. */ + break; + case 8: /* MMU TLB control. */ + switch (op2) { + case 0: /* Invalidate all. */ + tlb_flush(env, 0); + break; + case 1: /* Invalidate single TLB entry. */ +#if 0 + /* ??? This is wrong for large pages and sections. */ + /* As an ugly hack to make linux work we always flush a 4K + pages. */ + val &= 0xfffff000; + tlb_flush_page(env, val); + tlb_flush_page(env, val + 0x400); + tlb_flush_page(env, val + 0x800); + tlb_flush_page(env, val + 0xc00); +#else + tlb_flush(env, 1); +#endif + break; + case 2: /* Invalidate on ASID. */ + tlb_flush(env, val == 0); + break; + case 3: /* Invalidate single entry on MVA. */ + /* ??? This is like case 1, but ignores ASID. */ + tlb_flush(env, 1); + break; + default: + goto bad_reg; + } + break; + case 9: + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; + switch (crm) { + case 0: /* Cache lockdown. */ + switch (op1) { + case 0: /* L1 cache. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 1: /* L2 cache. */ + /* Ignore writes to L2 lockdown/auxiliary registers. */ + break; + default: + goto bad_reg; + } + break; + case 1: /* TCM memory region registers. */ + /* Not implemented. */ + goto bad_reg; + default: + goto bad_reg; + } + break; + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + break; + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + /* Unlike real hardware the qemu TLB uses virtual addresses, + not modified virtual addresses, so this causes a TLB flush. + */ + if (env->cp15.c13_fcse != val) + tlb_flush(env, 1); + env->cp15.c13_fcse = val; + break; + case 1: + /* This changes the ASID, so do a TLB flush. */ + if (env->cp15.c13_context != val + && !arm_feature(env, ARM_FEATURE_MPU)) + tlb_flush(env, 0); + env->cp15.c13_context = val; + break; + case 2: + env->cp15.c13_tls1 = val; + break; + case 3: + env->cp15.c13_tls2 = val; + break; + case 4: + env->cp15.c13_tls3 = val; + break; + default: + goto bad_reg; + } + break; + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && crm == 1) { + if (env->cp15.c15_cpar != (val & 0x3fff)) { + /* Changes cp0 to cp13 behavior, so needs a TB flush. */ + tb_flush(env); + env->cp15.c15_cpar = val & 0x3fff; + } + break; + } + goto bad_reg; + } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + break; + case 1: /* Set TI925T configuration. */ + env->cp15.c15_ticonfig = val & 0xe7; + env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */ + ARM_CPUID_TI915T : ARM_CPUID_TI925T; + break; + case 2: /* Set I_max. */ + env->cp15.c15_i_max = val; + break; + case 3: /* Set I_min. */ + env->cp15.c15_i_min = val; + break; + case 4: /* Set thread-ID. */ + env->cp15.c15_threadid = val & 0xffff; + break; + case 8: /* Wait-for-interrupt (deprecated). */ + cpu_interrupt(env, CPU_INTERRUPT_HALT); + break; + default: + goto bad_reg; + } + } + break; + } + return; +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); +} + +uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) +{ + int op1; + int op2; + int crm; + + op1 = (insn >> 21) & 7; + op2 = (insn >> 5) & 7; + crm = insn & 0xf; + switch ((insn >> 16) & 0xf) { + case 0: /* ID codes. */ + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: /* Device ID. */ + return env->cp15.c0_cpuid; + case 1: /* Cache Type. */ + return env->cp15.c0_cachetype; + case 2: /* TCM status. */ + return 0; + case 3: /* TLB type register. */ + return 0; /* No lockable TLB entries. */ + case 5: /* CPU ID */ + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) { + return env->cpu_index | 0x80000900; + } else { + return env->cpu_index; + } + default: + goto bad_reg; + } + case 1: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c1[op2]; + case 2: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c2[op2]; + case 3: case 4: case 5: case 6: case 7: + return 0; + default: + goto bad_reg; + } + case 1: + /* These registers aren't documented on arm11 cores. However + Linux looks at them anyway. */ + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + if (crm != 0) + goto bad_reg; + if (!arm_feature(env, ARM_FEATURE_V7)) + return 0; + + switch (op2) { + case 0: + return env->cp15.c0_ccsid[env->cp15.c0_cssel]; + case 1: + return env->cp15.c0_clid; + case 7: + return 0; + } + goto bad_reg; + case 2: + if (op2 != 0 || crm != 0) + goto bad_reg; + return env->cp15.c0_cssel; + default: + goto bad_reg; + } + case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: /* Control register. */ + return env->cp15.c1_sys; + case 1: /* Auxiliary control register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + return env->cp15.c1_xscaleauxcr; + if (!arm_feature(env, ARM_FEATURE_AUXCR)) + goto bad_reg; + switch (ARM_CPUID(env)) { + case ARM_CPUID_ARM1026: + return 1; + case ARM_CPUID_ARM1136: + case ARM_CPUID_ARM1136_R2: + return 7; + case ARM_CPUID_ARM11MPCORE: + return 1; + case ARM_CPUID_CORTEXA8: + return 2; + case ARM_CPUID_CORTEXA9: + return 0; + default: + goto bad_reg; + } + case 2: /* Coprocessor access register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; + return env->cp15.c1_coproc; + default: + goto bad_reg; + } + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + return env->cp15.c2_data; + break; + case 1: + return env->cp15.c2_insn; + break; + default: + goto bad_reg; + } + } else { + switch (op2) { + case 0: + return env->cp15.c2_base0; + case 1: + return env->cp15.c2_base1; + case 2: + return env->cp15.c2_control; + default: + goto bad_reg; + } + } + case 3: /* MMU Domain access control / MPU write buffer control. */ + return env->cp15.c3; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); + return env->cp15.c5_data; + case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); + return env->cp15.c5_insn; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + return env->cp15.c5_data; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + return env->cp15.c5_insn; + default: + goto bad_reg; + } + case 6: /* MMU Fault address. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + if (crm >= 8) + goto bad_reg; + return env->cp15.c6_region[crm]; + } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Watchpoint Fault Adrress. */ + return 0; /* Not implemented. */ + } else { + /* Instruction Fault Adrress. */ + /* Arm9 doesn't have an IFAR, but implementing it anyway + shouldn't do any harm. */ + return env->cp15.c6_insn; + } + case 2: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Instruction Fault Adrress. */ + return env->cp15.c6_insn; + } else { + goto bad_reg; + } + default: + goto bad_reg; + } + } + case 7: /* Cache control. */ + /* FIXME: Should only clear Z flag if destination is r15. */ + env->ZF = 0; + return 0; + case 8: /* MMU TLB control. */ + goto bad_reg; + case 9: /* Cache lockdown. */ + switch (op1) { + case 0: /* L1 cache. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + return 0; + switch (op2) { + case 0: + return env->cp15.c9_data; + case 1: + return env->cp15.c9_insn; + default: + goto bad_reg; + } + case 1: /* L2 cache */ + if (crm != 0) + goto bad_reg; + /* L2 Lockdown and Auxiliary control. */ + return 0; + default: + goto bad_reg; + } + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + return 0; + case 11: /* TCM DMA control. */ + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + return env->cp15.c13_fcse; + case 1: + return env->cp15.c13_context; + case 2: + return env->cp15.c13_tls1; + case 3: + return env->cp15.c13_tls2; + case 4: + return env->cp15.c13_tls3; + default: + goto bad_reg; + } + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && crm == 1) + return env->cp15.c15_cpar; + + goto bad_reg; + } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + return 0; + case 1: /* Read TI925T configuration. */ + return env->cp15.c15_ticonfig; + case 2: /* Read I_max. */ + return env->cp15.c15_i_max; + case 3: /* Read I_min. */ + return env->cp15.c15_i_min; + case 4: /* Read thread-ID. */ + return env->cp15.c15_threadid; + case 8: /* TI925T_status */ + return 0; + } + /* TODO: Peripheral port remap register: + * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt + * controller base address at $rn & ~0xfff and map size of + * 0x200 << ($rn & 0xfff), when MMU is off. */ + goto bad_reg; + } + return 0; + } +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); + return 0; +} + +void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + env->banked_r13[bank_number(mode)] = val; +} + +uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode) +{ + return env->banked_r13[bank_number(mode)]; +} + +uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg) +{ + switch (reg) { + case 0: /* APSR */ + return xpsr_read(env) & 0xf8000000; + case 1: /* IAPSR */ + return xpsr_read(env) & 0xf80001ff; + case 2: /* EAPSR */ + return xpsr_read(env) & 0xff00fc00; + case 3: /* xPSR */ + return xpsr_read(env) & 0xff00fdff; + case 5: /* IPSR */ + return xpsr_read(env) & 0x000001ff; + case 6: /* EPSR */ + return xpsr_read(env) & 0x0700fc00; + case 7: /* IEPSR */ + return xpsr_read(env) & 0x0700edff; + case 8: /* MSP */ + return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13]; + case 9: /* PSP */ + return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp; + case 16: /* PRIMASK */ + return (env->uncached_cpsr & CPSR_I) != 0; + case 17: /* FAULTMASK */ + return (env->uncached_cpsr & CPSR_F) != 0; + case 18: /* BASEPRI */ + case 19: /* BASEPRI_MAX */ + return env->v7m.basepri; + case 20: /* CONTROL */ + return env->v7m.control; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register read (%d)\n", reg); + return 0; + } +} + +void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) +{ + switch (reg) { + case 0: /* APSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 1: /* IAPSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 2: /* EAPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 3: /* xPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 5: /* IPSR */ + /* IPSR bits are readonly. */ + break; + case 6: /* EPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 7: /* IEPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 8: /* MSP */ + if (env->v7m.current_sp) + env->v7m.other_sp = val; + else + env->regs[13] = val; + break; + case 9: /* PSP */ + if (env->v7m.current_sp) + env->regs[13] = val; + else + env->v7m.other_sp = val; + break; + case 16: /* PRIMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_I; + else + env->uncached_cpsr &= ~CPSR_I; + break; + case 17: /* FAULTMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_F; + else + env->uncached_cpsr &= ~CPSR_F; + break; + case 18: /* BASEPRI */ + env->v7m.basepri = val & 0xff; + break; + case 19: /* BASEPRI_MAX */ + val &= 0xff; + if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0)) + env->v7m.basepri = val; + break; + case 20: /* CONTROL */ + env->v7m.control = val & 3; + switch_v7m_sp(env, (val & 2) != 0); + break; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register write (%d)\n", reg); + return; + } +} + +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque) +{ + if (cpnum < 0 || cpnum > 14) { + cpu_abort(env, "Bad coprocessor number: %i\n", cpnum); + return; + } + + env->cp[cpnum].cp_read = cp_read; + env->cp[cpnum].cp_write = cp_write; + env->cp[cpnum].opaque = opaque; +} + +#endif + +/* Note that signed overflow is undefined in C. The following routines are + careful to use unsigned types where modulo arithmetic is required. + Failure to do so _will_ break on newer gcc. */ + +/* Signed saturating arithmetic. */ + +/* Perform 16-bit signed saturating addition. */ +static inline uint16_t add16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a + b; + if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating addition. */ +static inline uint8_t add8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a + b; + if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +/* Perform 16-bit signed saturating subtraction. */ +static inline uint16_t sub16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a - b; + if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed saturating subtraction. */ +static inline uint8_t sub8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a - b; + if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); +#define PFX q + +#include "op_addsub.h" + +/* Unsigned saturating arithmetic. */ +static inline uint16_t add16_usat(uint16_t a, uint16_t b) +{ + uint16_t res; + res = a + b; + if (res < a) + res = 0xffff; + return res; +} + +static inline uint16_t sub16_usat(uint16_t a, uint16_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +static inline uint8_t add8_usat(uint8_t a, uint8_t b) +{ + uint8_t res; + res = a + b; + if (res < a) + res = 0xff; + return res; +} + +static inline uint8_t sub8_usat(uint8_t a, uint8_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); +#define PFX uq + +#include "op_addsub.h" + +/* Signed modulo arithmetic. */ +#define SARITH16(a, b, n, op) do { \ + int32_t sum; \ + sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ + RESULT(sum, n, 16); \ + if (sum >= 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SARITH8(a, b, n, op) do { \ + int32_t sum; \ + sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ + RESULT(sum, n, 8); \ + if (sum >= 0) \ + ge |= 1 << n; \ + } while(0) + + +#define ADD16(a, b, n) SARITH16(a, b, n, +) +#define SUB16(a, b, n) SARITH16(a, b, n, -) +#define ADD8(a, b, n) SARITH8(a, b, n, +) +#define SUB8(a, b, n) SARITH8(a, b, n, -) +#define PFX s +#define ARITH_GE + +#include "op_addsub.h" + +/* Unsigned modulo arithmetic. */ +#define ADD16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 1) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define ADD8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 1) \ + ge |= 1 << n; \ + } while(0) + +#define SUB16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SUB8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 0) \ + ge |= 1 << n; \ + } while(0) + +#define PFX u +#define ARITH_GE + +#include "op_addsub.h" + +/* Halved signed arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) +#define PFX sh + +#include "op_addsub.h" + +/* Halved unsigned arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define PFX uh + +#include "op_addsub.h" + +static inline uint8_t do_usad(uint8_t a, uint8_t b) +{ + if (a > b) + return a - b; + else + return b - a; +} + +/* Unsigned sum of absolute byte differences. */ +uint32_t HELPER(usad8)(uint32_t a, uint32_t b) +{ + uint32_t sum; + sum = do_usad(a, b); + sum += do_usad(a >> 8, b >> 8); + sum += do_usad(a >> 16, b >>16); + sum += do_usad(a >> 24, b >> 24); + return sum; +} + +/* For ARMv6 SEL instruction. */ +uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) +{ + uint32_t mask; + + mask = 0; + if (flags & 1) + mask |= 0xff; + if (flags & 2) + mask |= 0xff00; + if (flags & 4) + mask |= 0xff0000; + if (flags & 8) + mask |= 0xff000000; + return (a & mask) | (b & ~mask); +} + +uint32_t HELPER(logicq_cc)(uint64_t val) +{ + return (val >> 32) | (val != 0); +} + +/* VFP support. We follow the convention used for VFP instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to vfp form. */ +static inline int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) + target_bits |= 1; + if (host_bits & float_flag_divbyzero) + target_bits |= 2; + if (host_bits & float_flag_overflow) + target_bits |= 4; + if (host_bits & float_flag_underflow) + target_bits |= 8; + if (host_bits & float_flag_inexact) + target_bits |= 0x10; + return target_bits; +} + +uint32_t HELPER(vfp_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) + | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + i = get_float_exception_flags(&env->vfp.fp_status); + fpscr |= vfp_exceptbits_from_host(i); + return fpscr; +} + +/* Convert vfp exception flags to target form. */ +static inline int vfp_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & 1) + host_bits |= float_flag_invalid; + if (target_bits & 2) + host_bits |= float_flag_divbyzero; + if (target_bits & 4) + host_bits |= float_flag_overflow; + if (target_bits & 8) + host_bits |= float_flag_underflow; + if (target_bits & 0x10) + host_bits |= float_flag_inexact; + return host_bits; +} + +void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff); + env->vfp.vec_len = (val >> 16) & 7; + env->vfp.vec_stride = (val >> 20) & 3; + + changed ^= val; + if (changed & (3 << 22)) { + i = (val >> 22) & 3; + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_up; + break; + case 2: + i = float_round_down; + break; + case 3: + i = float_round_to_zero; + break; + } + set_float_rounding_mode(i, &env->vfp.fp_status); + } + if (changed & (1 << 24)) + set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); + if (changed & (1 << 25)) + set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); + + i = vfp_exceptbits_to_host((val >> 8) & 0x1f); + set_float_exception_flags(i, &env->vfp.fp_status); +} + +#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) + +#define VFP_BINOP(name) \ +float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \ +{ \ + return float32_ ## name (a, b, &env->vfp.fp_status); \ +} \ +float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \ +{ \ + return float64_ ## name (a, b, &env->vfp.fp_status); \ +} +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) +#undef VFP_BINOP + +float32 VFP_HELPER(neg, s)(float32 a) +{ + return float32_chs(a); +} + +float64 VFP_HELPER(neg, d)(float64 a) +{ + return float64_chs(a); +} + +float32 VFP_HELPER(abs, s)(float32 a) +{ + return float32_abs(a); +} + +float64 VFP_HELPER(abs, d)(float64 a) +{ + return float64_abs(a); +} + +float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env) +{ + return float32_sqrt(a, &env->vfp.fp_status); +} + +float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env) +{ + return float64_sqrt(a, &env->vfp.fp_status); +} + +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, type) \ +void VFP_HELPER(cmp, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} \ +void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} +DO_VFP_cmp(s, float32) +DO_VFP_cmp(d, float64) +#undef DO_VFP_cmp + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 vfp_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t vfp_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) +{ + return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) +{ + return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) +{ + return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) +{ + return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +/* Float to integer conversion. */ +float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +/* floating point conversion */ +float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->vfp.fp_status); +} + +float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->vfp.fp_status); +} + +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ +ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ + &env->vfp.fp_status); \ + return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \ +} \ +ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ + return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ + &env->vfp.fp_status)); \ +} + +VFP_CONV_FIX(sh, d, float64, int16, ) +VFP_CONV_FIX(sl, d, float64, int32, ) +VFP_CONV_FIX(uh, d, float64, uint16, u) +VFP_CONV_FIX(ul, d, float64, uint32, u) +VFP_CONV_FIX(sh, s, float32, int16, ) +VFP_CONV_FIX(sl, s, float32, int32, ) +VFP_CONV_FIX(uh, s, float32, uint16, u) +VFP_CONV_FIX(ul, s, float32, uint32, u) +#undef VFP_CONV_FIX + +/* Half precision conversions. */ +float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; + return float16_to_float32(a, ieee, s); +} + +uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; + return float32_to_float16(a, ieee, s); +} + +float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 two = int32_to_float32(2, s); + return float32_sub(two, float32_mul(a, b, s), s); +} + +float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 three = int32_to_float32(3, s); + return float32_sub(three, float32_mul(a, b, s), s); +} + +/* NEON helpers. */ + +/* TODO: The architecture specifies the value that the estimate functions + should return. We return the exact reciprocal/root instead. */ +float32 HELPER(recpe_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, a, s); +} + +float32 HELPER(rsqrte_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, float32_sqrt(a, s), s); +} + +uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_recpe_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_rsqrte_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +void HELPER(set_teecr)(CPUState *env, uint32_t val) +{ + val &= 1; + if (env->teecr != val) { + env->teecr = val; + tb_flush(env); + } +} diff --git a/qemu/qemu-git/target-arm/helpers.h b/qemu/qemu-git/target-arm/helpers.h new file mode 100644 index 0000000..0d1bc47 --- /dev/null +++ b/qemu/qemu-git/target-arm/helpers.h @@ -0,0 +1,450 @@ +#include "def-helper.h" + +DEF_HELPER_1(clz, i32, i32) +DEF_HELPER_1(sxtb16, i32, i32) +DEF_HELPER_1(uxtb16, i32, i32) + +DEF_HELPER_2(add_setq, i32, i32, i32) +DEF_HELPER_2(add_saturate, i32, i32, i32) +DEF_HELPER_2(sub_saturate, i32, i32, i32) +DEF_HELPER_2(add_usaturate, i32, i32, i32) +DEF_HELPER_2(sub_usaturate, i32, i32, i32) +DEF_HELPER_1(double_saturate, i32, s32) +DEF_HELPER_2(sdiv, s32, s32, s32) +DEF_HELPER_2(udiv, i32, i32, i32) +DEF_HELPER_1(rbit, i32, i32) +DEF_HELPER_1(abs, i32, i32) + +#define PAS_OP(pfx) \ + DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr) + +PAS_OP(s) +PAS_OP(u) +#undef PAS_OP + +#define PAS_OP(pfx) \ + DEF_HELPER_2(pfx ## add8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## add16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \ + DEF_HELPER_2(pfx ## subaddx, i32, i32, i32) +PAS_OP(q) +PAS_OP(sh) +PAS_OP(uq) +PAS_OP(uh) +#undef PAS_OP + +DEF_HELPER_2(ssat, i32, i32, i32) +DEF_HELPER_2(usat, i32, i32, i32) +DEF_HELPER_2(ssat16, i32, i32, i32) +DEF_HELPER_2(usat16, i32, i32, i32) + +DEF_HELPER_2(usad8, i32, i32, i32) + +DEF_HELPER_1(logicq_cc, i32, i64) + +DEF_HELPER_3(sel_flags, i32, i32, i32, i32) +DEF_HELPER_1(exception, void, i32) +DEF_HELPER_0(wfi, void) + +DEF_HELPER_2(cpsr_write, void, i32, i32) +DEF_HELPER_0(cpsr_read, i32) + +DEF_HELPER_3(v7m_msr, void, env, i32, i32) +DEF_HELPER_2(v7m_mrs, i32, env, i32) + +DEF_HELPER_3(set_cp15, void, env, i32, i32) +DEF_HELPER_2(get_cp15, i32, env, i32) + +DEF_HELPER_3(set_cp, void, env, i32, i32) +DEF_HELPER_2(get_cp, i32, env, i32) + +DEF_HELPER_2(get_r13_banked, i32, env, i32) +DEF_HELPER_3(set_r13_banked, void, env, i32, i32) + +DEF_HELPER_1(get_user_reg, i32, i32) +DEF_HELPER_2(set_user_reg, void, i32, i32) + +DEF_HELPER_1(vfp_get_fpscr, i32, env) +DEF_HELPER_2(vfp_set_fpscr, void, env, i32) + +DEF_HELPER_3(vfp_adds, f32, f32, f32, env) +DEF_HELPER_3(vfp_addd, f64, f64, f64, env) +DEF_HELPER_3(vfp_subs, f32, f32, f32, env) +DEF_HELPER_3(vfp_subd, f64, f64, f64, env) +DEF_HELPER_3(vfp_muls, f32, f32, f32, env) +DEF_HELPER_3(vfp_muld, f64, f64, f64, env) +DEF_HELPER_3(vfp_divs, f32, f32, f32, env) +DEF_HELPER_3(vfp_divd, f64, f64, f64, env) +DEF_HELPER_1(vfp_negs, f32, f32) +DEF_HELPER_1(vfp_negd, f64, f64) +DEF_HELPER_1(vfp_abss, f32, f32) +DEF_HELPER_1(vfp_absd, f64, f64) +DEF_HELPER_2(vfp_sqrts, f32, f32, env) +DEF_HELPER_2(vfp_sqrtd, f64, f64, env) +DEF_HELPER_3(vfp_cmps, void, f32, f32, env) +DEF_HELPER_3(vfp_cmpd, void, f64, f64, env) +DEF_HELPER_3(vfp_cmpes, void, f32, f32, env) +DEF_HELPER_3(vfp_cmped, void, f64, f64, env) + +DEF_HELPER_2(vfp_fcvtds, f64, f32, env) +DEF_HELPER_2(vfp_fcvtsd, f32, f64, env) + +DEF_HELPER_2(vfp_uitos, f32, f32, env) +DEF_HELPER_2(vfp_uitod, f64, f32, env) +DEF_HELPER_2(vfp_sitos, f32, f32, env) +DEF_HELPER_2(vfp_sitod, f64, f32, env) + +DEF_HELPER_2(vfp_touis, f32, f32, env) +DEF_HELPER_2(vfp_touid, f32, f64, env) +DEF_HELPER_2(vfp_touizs, f32, f32, env) +DEF_HELPER_2(vfp_touizd, f32, f64, env) +DEF_HELPER_2(vfp_tosis, f32, f32, env) +DEF_HELPER_2(vfp_tosid, f32, f64, env) +DEF_HELPER_2(vfp_tosizs, f32, f32, env) +DEF_HELPER_2(vfp_tosizd, f32, f64, env) + +DEF_HELPER_3(vfp_toshs, f32, f32, i32, env) +DEF_HELPER_3(vfp_tosls, f32, f32, i32, env) +DEF_HELPER_3(vfp_touhs, f32, f32, i32, env) +DEF_HELPER_3(vfp_touls, f32, f32, i32, env) +DEF_HELPER_3(vfp_toshd, f64, f64, i32, env) +DEF_HELPER_3(vfp_tosld, f64, f64, i32, env) +DEF_HELPER_3(vfp_touhd, f64, f64, i32, env) +DEF_HELPER_3(vfp_tould, f64, f64, i32, env) +DEF_HELPER_3(vfp_shtos, f32, f32, i32, env) +DEF_HELPER_3(vfp_sltos, f32, f32, i32, env) +DEF_HELPER_3(vfp_uhtos, f32, f32, i32, env) +DEF_HELPER_3(vfp_ultos, f32, f32, i32, env) +DEF_HELPER_3(vfp_shtod, f64, f64, i32, env) +DEF_HELPER_3(vfp_sltod, f64, f64, i32, env) +DEF_HELPER_3(vfp_uhtod, f64, f64, i32, env) +DEF_HELPER_3(vfp_ultod, f64, f64, i32, env) + +DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env) +DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env) + +DEF_HELPER_3(recps_f32, f32, f32, f32, env) +DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env) +DEF_HELPER_2(recpe_f32, f32, f32, env) +DEF_HELPER_2(rsqrte_f32, f32, f32, env) +DEF_HELPER_2(recpe_u32, i32, i32, env) +DEF_HELPER_2(rsqrte_u32, i32, i32, env) +DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32) +DEF_HELPER_2(neon_add_saturate_u64, i64, i64, i64) +DEF_HELPER_2(neon_add_saturate_s64, i64, i64, i64) +DEF_HELPER_2(neon_sub_saturate_u64, i64, i64, i64) +DEF_HELPER_2(neon_sub_saturate_s64, i64, i64, i64) + +DEF_HELPER_2(add_cc, i32, i32, i32) +DEF_HELPER_2(adc_cc, i32, i32, i32) +DEF_HELPER_2(sub_cc, i32, i32, i32) +DEF_HELPER_2(sbc_cc, i32, i32, i32) + +DEF_HELPER_2(shl, i32, i32, i32) +DEF_HELPER_2(shr, i32, i32, i32) +DEF_HELPER_2(sar, i32, i32, i32) +DEF_HELPER_2(shl_cc, i32, i32, i32) +DEF_HELPER_2(shr_cc, i32, i32, i32) +DEF_HELPER_2(sar_cc, i32, i32, i32) +DEF_HELPER_2(ror_cc, i32, i32, i32) + +/* neon_helper.c */ +DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32) + +DEF_HELPER_2(neon_hadd_s8, i32, i32, i32) +DEF_HELPER_2(neon_hadd_u8, i32, i32, i32) +DEF_HELPER_2(neon_hadd_s16, i32, i32, i32) +DEF_HELPER_2(neon_hadd_u16, i32, i32, i32) +DEF_HELPER_2(neon_hadd_s32, s32, s32, s32) +DEF_HELPER_2(neon_hadd_u32, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32) +DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32) +DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s8, i32, i32, i32) +DEF_HELPER_2(neon_hsub_u8, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s16, i32, i32, i32) +DEF_HELPER_2(neon_hsub_u16, i32, i32, i32) +DEF_HELPER_2(neon_hsub_s32, s32, s32, s32) +DEF_HELPER_2(neon_hsub_u32, i32, i32, i32) + +DEF_HELPER_2(neon_cgt_u8, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s8, i32, i32, i32) +DEF_HELPER_2(neon_cgt_u16, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s16, i32, i32, i32) +DEF_HELPER_2(neon_cgt_u32, i32, i32, i32) +DEF_HELPER_2(neon_cgt_s32, i32, i32, i32) +DEF_HELPER_2(neon_cge_u8, i32, i32, i32) +DEF_HELPER_2(neon_cge_s8, i32, i32, i32) +DEF_HELPER_2(neon_cge_u16, i32, i32, i32) +DEF_HELPER_2(neon_cge_s16, i32, i32, i32) +DEF_HELPER_2(neon_cge_u32, i32, i32, i32) +DEF_HELPER_2(neon_cge_s32, i32, i32, i32) + +DEF_HELPER_2(neon_min_u8, i32, i32, i32) +DEF_HELPER_2(neon_min_s8, i32, i32, i32) +DEF_HELPER_2(neon_min_u16, i32, i32, i32) +DEF_HELPER_2(neon_min_s16, i32, i32, i32) +DEF_HELPER_2(neon_min_u32, i32, i32, i32) +DEF_HELPER_2(neon_min_s32, i32, i32, i32) +DEF_HELPER_2(neon_max_u8, i32, i32, i32) +DEF_HELPER_2(neon_max_s8, i32, i32, i32) +DEF_HELPER_2(neon_max_u16, i32, i32, i32) +DEF_HELPER_2(neon_max_s16, i32, i32, i32) +DEF_HELPER_2(neon_max_u32, i32, i32, i32) +DEF_HELPER_2(neon_max_s32, i32, i32, i32) +DEF_HELPER_2(neon_pmin_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s16, i32, i32, i32) + +DEF_HELPER_2(neon_abd_u8, i32, i32, i32) +DEF_HELPER_2(neon_abd_s8, i32, i32, i32) +DEF_HELPER_2(neon_abd_u16, i32, i32, i32) +DEF_HELPER_2(neon_abd_s16, i32, i32, i32) +DEF_HELPER_2(neon_abd_u32, i32, i32, i32) +DEF_HELPER_2(neon_abd_s32, i32, i32, i32) + +DEF_HELPER_2(neon_shl_u8, i32, i32, i32) +DEF_HELPER_2(neon_shl_s8, i32, i32, i32) +DEF_HELPER_2(neon_shl_u16, i32, i32, i32) +DEF_HELPER_2(neon_shl_s16, i32, i32, i32) +DEF_HELPER_2(neon_shl_u32, i32, i32, i32) +DEF_HELPER_2(neon_shl_s32, i32, i32, i32) +DEF_HELPER_2(neon_shl_u64, i64, i64, i64) +DEF_HELPER_2(neon_shl_s64, i64, i64, i64) +DEF_HELPER_2(neon_rshl_u8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u64, i64, i64, i64) +DEF_HELPER_2(neon_rshl_s64, i64, i64, i64) +DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64) + +DEF_HELPER_2(neon_add_u8, i32, i32, i32) +DEF_HELPER_2(neon_add_u16, i32, i32, i32) +DEF_HELPER_2(neon_padd_u8, i32, i32, i32) +DEF_HELPER_2(neon_padd_u16, i32, i32, i32) +DEF_HELPER_2(neon_sub_u8, i32, i32, i32) +DEF_HELPER_2(neon_sub_u16, i32, i32, i32) +DEF_HELPER_2(neon_mul_u8, i32, i32, i32) +DEF_HELPER_2(neon_mul_u16, i32, i32, i32) +DEF_HELPER_2(neon_mul_p8, i32, i32, i32) + +DEF_HELPER_2(neon_tst_u8, i32, i32, i32) +DEF_HELPER_2(neon_tst_u16, i32, i32, i32) +DEF_HELPER_2(neon_tst_u32, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u8, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u16, i32, i32, i32) +DEF_HELPER_2(neon_ceq_u32, i32, i32, i32) + +DEF_HELPER_1(neon_abs_s8, i32, i32) +DEF_HELPER_1(neon_abs_s16, i32, i32) +DEF_HELPER_1(neon_clz_u8, i32, i32) +DEF_HELPER_1(neon_clz_u16, i32, i32) +DEF_HELPER_1(neon_cls_s8, i32, i32) +DEF_HELPER_1(neon_cls_s16, i32, i32) +DEF_HELPER_1(neon_cls_s32, i32, i32) +DEF_HELPER_1(neon_cnt_u8, i32, i32) + +DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) + +DEF_HELPER_1(neon_narrow_u8, i32, i64) +DEF_HELPER_1(neon_narrow_u16, i32, i64) +DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64) +DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64) +DEF_HELPER_1(neon_narrow_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_high_u16, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64) +DEF_HELPER_1(neon_widen_u8, i64, i32) +DEF_HELPER_1(neon_widen_s8, i64, i32) +DEF_HELPER_1(neon_widen_u16, i64, i32) +DEF_HELPER_1(neon_widen_s16, i64, i32) + +DEF_HELPER_2(neon_addl_u16, i64, i64, i64) +DEF_HELPER_2(neon_addl_u32, i64, i64, i64) +DEF_HELPER_2(neon_paddl_u16, i64, i64, i64) +DEF_HELPER_2(neon_paddl_u32, i64, i64, i64) +DEF_HELPER_2(neon_subl_u16, i64, i64, i64) +DEF_HELPER_2(neon_subl_u32, i64, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u64, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s64, i64, i32, i32) +DEF_HELPER_2(neon_mull_u8, i64, i32, i32) +DEF_HELPER_2(neon_mull_s8, i64, i32, i32) +DEF_HELPER_2(neon_mull_u16, i64, i32, i32) +DEF_HELPER_2(neon_mull_s16, i64, i32, i32) + +DEF_HELPER_1(neon_negl_u16, i64, i64) +DEF_HELPER_1(neon_negl_u32, i64, i64) +DEF_HELPER_1(neon_negl_u64, i64, i64) + +DEF_HELPER_2(neon_qabs_s8, i32, env, i32) +DEF_HELPER_2(neon_qabs_s16, i32, env, i32) +DEF_HELPER_2(neon_qabs_s32, i32, env, i32) +DEF_HELPER_2(neon_qneg_s8, i32, env, i32) +DEF_HELPER_2(neon_qneg_s16, i32, env, i32) +DEF_HELPER_2(neon_qneg_s32, i32, env, i32) + +DEF_HELPER_2(neon_min_f32, i32, i32, i32) +DEF_HELPER_2(neon_max_f32, i32, i32, i32) +DEF_HELPER_2(neon_abd_f32, i32, i32, i32) +DEF_HELPER_2(neon_add_f32, i32, i32, i32) +DEF_HELPER_2(neon_sub_f32, i32, i32, i32) +DEF_HELPER_2(neon_mul_f32, i32, i32, i32) +DEF_HELPER_2(neon_ceq_f32, i32, i32, i32) +DEF_HELPER_2(neon_cge_f32, i32, i32, i32) +DEF_HELPER_2(neon_cgt_f32, i32, i32, i32) +DEF_HELPER_2(neon_acge_f32, i32, i32, i32) +DEF_HELPER_2(neon_acgt_f32, i32, i32, i32) + +/* iwmmxt_helper.c */ +DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64) +DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64) + +#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ +DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \ + +DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) +DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) + +DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64) + +DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) + +DEF_IWMMXT_HELPER_SIZE_ENV(mins) +DEF_IWMMXT_HELPER_SIZE_ENV(minu) +DEF_IWMMXT_HELPER_SIZE_ENV(maxs) +DEF_IWMMXT_HELPER_SIZE_ENV(maxu) + +DEF_IWMMXT_HELPER_SIZE_ENV(subn) +DEF_IWMMXT_HELPER_SIZE_ENV(addn) +DEF_IWMMXT_HELPER_SIZE_ENV(subu) +DEF_IWMMXT_HELPER_SIZE_ENV(addu) +DEF_IWMMXT_HELPER_SIZE_ENV(subs) +DEF_IWMMXT_HELPER_SIZE_ENV(adds) + +DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64) + +DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64) + +DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32) +DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32) + +DEF_HELPER_1(iwmmxt_bcstb, i64, i32) +DEF_HELPER_1(iwmmxt_bcstw, i64, i32) +DEF_HELPER_1(iwmmxt_bcstl, i64, i32) + +DEF_HELPER_1(iwmmxt_addcb, i64, i64) +DEF_HELPER_1(iwmmxt_addcw, i64, i64) +DEF_HELPER_1(iwmmxt_addcl, i64, i64) + +DEF_HELPER_1(iwmmxt_msbb, i32, i64) +DEF_HELPER_1(iwmmxt_msbw, i32, i64) +DEF_HELPER_1(iwmmxt_msbl, i32, i64) + +DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32) + +DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64) + +DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) + +DEF_HELPER_2(set_teecr, void, env, i32) + +#include "def-helper.h" diff --git a/qemu/qemu-git/target-arm/iwmmxt_helper.c b/qemu/qemu-git/target-arm/iwmmxt_helper.c new file mode 100644 index 0000000..3332f70 --- /dev/null +++ b/qemu/qemu-git/target-arm/iwmmxt_helper.c @@ -0,0 +1,681 @@ +/* + * iwMMXt micro operations for XScale. + * + * Copyright (c) 2007 OpenedHand, Ltd. + * Written by Andrzej Zaborowski + * Copyright (c) 2008 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +/* iwMMXt macros extracted from GNU gdb. */ + +/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ +#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n))) +#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n))) +#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n))) +#define SIMD64_SET(v, n) ((v != 0) << (32 + (n))) +/* Flags to pass as "n" above. */ +#define SIMD_NBIT -1 +#define SIMD_ZBIT -2 +#define SIMD_CBIT -3 +#define SIMD_VBIT -4 +/* Various status bit macros. */ +#define NBIT8(x) ((x) & 0x80) +#define NBIT16(x) ((x) & 0x8000) +#define NBIT32(x) ((x) & 0x80000000) +#define NBIT64(x) ((x) & 0x8000000000000000ULL) +#define ZBIT8(x) (((x) & 0xff) == 0) +#define ZBIT16(x) (((x) & 0xffff) == 0) +#define ZBIT32(x) (((x) & 0xffffffff) == 0) +#define ZBIT64(x) (x == 0) +/* Sign extension macros. */ +#define EXTEND8H(a) ((uint16_t) (int8_t) (a)) +#define EXTEND8(a) ((uint32_t) (int8_t) (a)) +#define EXTEND16(a) ((uint32_t) (int16_t) (a)) +#define EXTEND16S(a) ((int32_t) (int16_t) (a)) +#define EXTEND32(a) ((uint64_t) (int32_t) (a)) + +uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b) +{ + a = (( + EXTEND16S((a >> 0) & 0xffff) * EXTEND16S((b >> 0) & 0xffff) + + EXTEND16S((a >> 16) & 0xffff) * EXTEND16S((b >> 16) & 0xffff) + ) & 0xffffffff) | ((uint64_t) ( + EXTEND16S((a >> 32) & 0xffff) * EXTEND16S((b >> 32) & 0xffff) + + EXTEND16S((a >> 48) & 0xffff) * EXTEND16S((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_madduq)(uint64_t a, uint64_t b) +{ + a = (( + ((a >> 0) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff) + ) & 0xffffffff) | (( + ((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff) + ) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_sadb)(uint64_t a, uint64_t b) +{ +#define abs(x) (((x) >= 0) ? x : -x) +#define SADB(SHR) abs((int) ((a >> SHR) & 0xff) - (int) ((b >> SHR) & 0xff)) + return + SADB(0) + SADB(8) + SADB(16) + SADB(24) + + SADB(32) + SADB(40) + SADB(48) + SADB(56); +#undef SADB +} + +uint64_t HELPER(iwmmxt_sadw)(uint64_t a, uint64_t b) +{ +#define SADW(SHR) \ + abs((int) ((a >> SHR) & 0xffff) - (int) ((b >> SHR) & 0xffff)) + return SADW(0) + SADW(16) + SADW(32) + SADW(48); +#undef SADW +} + +uint64_t HELPER(iwmmxt_mulslw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mulshw)(uint64_t a, uint64_t b) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +uint64_t HELPER(iwmmxt_mululw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 0) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_muluhw)(uint64_t a, uint64_t b) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \ + ) >> 16) & 0xffff) << SHR) + return MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +uint64_t HELPER(iwmmxt_macsw)(uint64_t a, uint64_t b) +{ +#define MACS(SHR) ( \ + EXTEND16((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff)) + return (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); +#undef MACS +} + +uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b) +{ +#define MACU(SHR) ( \ + (uint32_t) ((a >> SHR) & 0xffff) * \ + (uint32_t) ((b >> SHR) & 0xffff)) + return MACU(0) + MACU(16) + MACU(32) + MACU(48); +#undef MACU +} + +#define NZBIT8(x, i) \ + SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \ + SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i) +#define NZBIT16(x, i) \ + SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \ + SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i) +#define NZBIT32(x, i) \ + SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \ + SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i) +#define NZBIT64(x) \ + SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ + SIMD64_SET(ZBIT64(x), SIMD_ZBIT) +#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \ + (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \ + (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \ + (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffff) << 0) | \ + (((b >> SH0) & 0xffff) << 16) | \ + (((a >> SH2) & 0xffff) << 32) | \ + (((b >> SH2) & 0xffff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \ + NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + (((a >> SH0) & 0xffffffff) << 0) | \ + (((b >> SH0) & 0xffffffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xff) << 0) | \ + (((x >> SH1) & 0xff) << 16) | \ + (((x >> SH2) & 0xff) << 32) | \ + (((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + (((x >> SH0) & 0xffff) << 0) | \ + (((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = (((x >> SH0) & 0xffffffff) << 0); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \ + ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \ + ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \ + ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \ + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = \ + ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \ + ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ + return x; \ +} \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \ + uint64_t x) \ +{ \ + x = EXTEND32((x >> SH0) & 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ + return x; \ +} +IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) +IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) + +#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = \ + CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ + CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \ + CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \ + CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \ + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \ + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \ + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ + CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \ + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \ + return a; \ +} \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env, \ + uint64_t a, uint64_t b) \ +{ \ + a = CMP(0, Tl, O, 0xffffffff) | \ + CMP(32, Tl, O, 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ + return a; \ +} +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR) +IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==) +IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \ + (TYPE) ((b >> SHR) & MASK)) ? a : b) & ((uint64_t) MASK << SHR)) +IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <) +IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <) +IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +) +#undef CMP +/* TODO Signed- and Unsigned-Saturation */ +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \ + OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +) +IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -) +IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) +#undef CMP +#undef IWMMXT_OP_CMP + +#define AVGB(SHR) ((( \ + ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGB(r) \ +uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | \ + AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD8_SET(ZBIT8((a >> 0) & 0xff), SIMD_ZBIT, 0) | \ + SIMD8_SET(ZBIT8((a >> 8) & 0xff), SIMD_ZBIT, 1) | \ + SIMD8_SET(ZBIT8((a >> 16) & 0xff), SIMD_ZBIT, 2) | \ + SIMD8_SET(ZBIT8((a >> 24) & 0xff), SIMD_ZBIT, 3) | \ + SIMD8_SET(ZBIT8((a >> 32) & 0xff), SIMD_ZBIT, 4) | \ + SIMD8_SET(ZBIT8((a >> 40) & 0xff), SIMD_ZBIT, 5) | \ + SIMD8_SET(ZBIT8((a >> 48) & 0xff), SIMD_ZBIT, 6) | \ + SIMD8_SET(ZBIT8((a >> 56) & 0xff), SIMD_ZBIT, 7); \ + return a; \ +} +IWMMXT_OP_AVGB(0) +IWMMXT_OP_AVGB(1) +#undef IWMMXT_OP_AVGB +#undef AVGB + +#define AVGW(SHR) ((( \ + ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR) +#define IWMMXT_OP_AVGW(r) \ +uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b) \ +{ \ + const int round = r; \ + a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + SIMD16_SET(ZBIT16((a >> 0) & 0xffff), SIMD_ZBIT, 0) | \ + SIMD16_SET(ZBIT16((a >> 16) & 0xffff), SIMD_ZBIT, 1) | \ + SIMD16_SET(ZBIT16((a >> 32) & 0xffff), SIMD_ZBIT, 2) | \ + SIMD16_SET(ZBIT16((a >> 48) & 0xffff), SIMD_ZBIT, 3); \ + return a; \ +} +IWMMXT_OP_AVGW(0) +IWMMXT_OP_AVGW(1) +#undef IWMMXT_OP_AVGW +#undef AVGW + +uint64_t HELPER(iwmmxt_msadb)(uint64_t a, uint64_t b) +{ + a = ((((a >> 0 ) & 0xffff) * ((b >> 0) & 0xffff) + + ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)) & 0xffffffff) | + ((((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) + + ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)) << 32); + return a; +} + +uint64_t HELPER(iwmmxt_align)(uint64_t a, uint64_t b, uint32_t n) +{ + a >>= n << 3; + a |= b << (64 - (n << 3)); + return a; +} + +uint64_t HELPER(iwmmxt_insr)(uint64_t x, uint32_t a, uint32_t b, uint32_t n) +{ + x &= ~((uint64_t) b << n); + x |= (uint64_t) (a & b) << n; + return x; +} + +uint32_t HELPER(iwmmxt_setpsr_nz)(uint64_t x) +{ + return SIMD64_SET((x == 0), SIMD_ZBIT) | + SIMD64_SET((x & (1ULL << 63)), SIMD_NBIT); +} + +uint64_t HELPER(iwmmxt_bcstb)(uint32_t arg) +{ + arg &= 0xff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 8 ) | + ((uint64_t) arg << 16) | ((uint64_t) arg << 24) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 40) | + ((uint64_t) arg << 48) | ((uint64_t) arg << 56); +} + +uint64_t HELPER(iwmmxt_bcstw)(uint32_t arg) +{ + arg &= 0xffff; + return + ((uint64_t) arg << 0 ) | ((uint64_t) arg << 16) | + ((uint64_t) arg << 32) | ((uint64_t) arg << 48); +} + +uint64_t HELPER(iwmmxt_bcstl)(uint32_t arg) +{ + return arg | ((uint64_t) arg << 32); +} + +uint64_t HELPER(iwmmxt_addcb)(uint64_t x) +{ + return + ((x >> 0) & 0xff) + ((x >> 8) & 0xff) + + ((x >> 16) & 0xff) + ((x >> 24) & 0xff) + + ((x >> 32) & 0xff) + ((x >> 40) & 0xff) + + ((x >> 48) & 0xff) + ((x >> 56) & 0xff); +} + +uint64_t HELPER(iwmmxt_addcw)(uint64_t x) +{ + return + ((x >> 0) & 0xffff) + ((x >> 16) & 0xffff) + + ((x >> 32) & 0xffff) + ((x >> 48) & 0xffff); +} + +uint64_t HELPER(iwmmxt_addcl)(uint64_t x) +{ + return (x & 0xffffffff) + (x >> 32); +} + +uint32_t HELPER(iwmmxt_msbb)(uint64_t x) +{ + return + ((x >> 7) & 0x01) | ((x >> 14) & 0x02) | + ((x >> 21) & 0x04) | ((x >> 28) & 0x08) | + ((x >> 35) & 0x10) | ((x >> 42) & 0x20) | + ((x >> 49) & 0x40) | ((x >> 56) & 0x80); +} + +uint32_t HELPER(iwmmxt_msbw)(uint64_t x) +{ + return + ((x >> 15) & 0x01) | ((x >> 30) & 0x02) | + ((x >> 45) & 0x04) | ((x >> 52) & 0x08); +} + +uint32_t HELPER(iwmmxt_msbl)(uint64_t x) +{ + return ((x >> 31) & 0x01) | ((x >> 62) & 0x02); +} + +/* FIXME: Split wCASF setting into a separate op to avoid env use. */ +uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) >> n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) >> n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n) +{ + x >>= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) | + (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) | + (((x & (0xffffll << 32)) << n) & (0xffffll << 32)) | + (((x & (0xffffll << 48)) << n) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x << n) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << n); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n) +{ + x <<= n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) | + ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) | + ((uint64_t) ((EXTEND16(x >> 32) >> n) & 0xffff) << 32) | + ((uint64_t) ((EXTEND16(x >> 48) >> n) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) | + (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (int64_t) x >> n; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((((x & (0xffffll << 0)) >> n) | + ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) | + ((((x & (0xffffll << 16)) >> n) | + ((x & (0xffffll << 16)) << (16 - n))) & (0xffffll << 16)) | + ((((x & (0xffffll << 32)) >> n) | + ((x & (0xffffll << 32)) << (16 - n))) & (0xffffll << 32)) | + ((((x & (0xffffll << 48)) >> n) | + ((x & (0xffffll << 48)) << (16 - n))) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n) +{ + x = ((x & (0xffffffffll << 0)) >> n) | + ((x >> n) & (0xffffffffll << 32)) | + ((x << (32 - n)) & (0xffffffffll << 0)) | + ((x & (0xffffffffll << 32)) << (32 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); + return x; +} + +uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (x >> n) | (x << (64 - n)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); + return x; +} + +uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n) +{ + x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) | + (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) | + (((x >> ((n << 0) & 0x30)) & 0xffff) << 32) | + (((x >> ((n >> 2) & 0x30)) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | + NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); + return x; +} + +/* TODO: Unsigned-Saturation */ +uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +/* TODO: Signed-Saturation */ +uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | + (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | + (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) | + (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | + NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | + NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | + NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); + return a; +} + +uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | + (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | + NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); + return a; +} + +uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b) +{ + a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); + return a; +} + +uint64_t HELPER(iwmmxt_muladdsl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + ((int32_t) EXTEND32(a) * (int32_t) EXTEND32(b)); +} + +uint64_t HELPER(iwmmxt_muladdsw)(uint64_t c, uint32_t a, uint32_t b) +{ + c += EXTEND32(EXTEND16S((a >> 0) & 0xffff) * + EXTEND16S((b >> 0) & 0xffff)); + c += EXTEND32(EXTEND16S((a >> 16) & 0xffff) * + EXTEND16S((b >> 16) & 0xffff)); + return c; +} + +uint64_t HELPER(iwmmxt_muladdswl)(uint64_t c, uint32_t a, uint32_t b) +{ + return c + (EXTEND32(EXTEND16S(a & 0xffff) * + EXTEND16S(b & 0xffff))); +} diff --git a/qemu/qemu-git/target-arm/neon_helper.c b/qemu/qemu-git/target-arm/neon_helper.c new file mode 100644 index 0000000..5e6452b --- /dev/null +++ b/qemu/qemu-git/target-arm/neon_helper.c @@ -0,0 +1,1459 @@ +/* + * ARM NEON vector operations. + * + * Copyright (c) 2007, 2008 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GNU GPL v2. + */ +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q + +static float_status neon_float_status; +#define NFS &neon_float_status + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +#define NEON_TYPE1(name, type) \ +typedef struct \ +{ \ + type v1; \ +} neon_##name; +#ifdef HOST_WORDS_BIGENDIAN +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v2; \ + type v1; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v4; \ + type v3; \ + type v2; \ + type v1; \ +} neon_##name; +#else +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ + type v3; \ + type v4; \ +} neon_##name; +#endif + +NEON_TYPE4(s8, int8_t) +NEON_TYPE4(u8, uint8_t) +NEON_TYPE2(s16, int16_t) +NEON_TYPE2(u16, uint16_t) +NEON_TYPE1(s32, int32_t) +NEON_TYPE1(u32, uint32_t) +#undef NEON_TYPE4 +#undef NEON_TYPE2 +#undef NEON_TYPE1 + +/* Copy from a uint32_t to a vector structure type. */ +#define NEON_UNPACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.i = (val); \ + dest = conv_u.v; \ + } while(0) + +/* Copy from a vector structure type to a uint32_t. */ +#define NEON_PACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.v = (val); \ + dest = conv_u.i; \ + } while(0) + +#define NEON_DO1 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); +#define NEON_DO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); +#define NEON_DO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \ + NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \ + NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4); + +#define NEON_VOP_BODY(vtype, n) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_DO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +#define NEON_VOP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +#define NEON_VOP_ENV(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \ +NEON_VOP_BODY(vtype, n) + +/* Pairwise operations. */ +/* For 32-bit elements each segment only contains a single element, so + the elementwise and pairwise operations are the same. */ +#define NEON_PDO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2); +#define NEON_PDO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \ + NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \ + NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \ + +#define NEON_POP(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ +{ \ + uint32_t res; \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg1); \ + NEON_UNPACK(vtype, vsrc2, arg2); \ + NEON_PDO##n; \ + NEON_PACK(vtype, res, vdest); \ + return res; \ +} + +/* Unary operators. */ +#define NEON_VOP1(name, vtype, n) \ +uint32_t HELPER(glue(neon_,name))(uint32_t arg) \ +{ \ + vtype vsrc1; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, arg); \ + NEON_DO##n; \ + NEON_PACK(vtype, arg, vdest); \ + return arg; \ +} + + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qadd_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qadd_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 > 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qadd_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qadd_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + dest = 0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP_ENV(qsub_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP_ENV(qsub_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + SET_QC(); \ + if (src2 < 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP_ENV(qsub_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP_ENV(qsub_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 +NEON_VOP(hadd_s8, neon_s8, 4) +NEON_VOP(hadd_u8, neon_u8, 4) +NEON_VOP(hadd_s16, neon_s16, 2) +NEON_VOP(hadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_hadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1 +NEON_VOP(rhadd_s8, neon_s8, 4) +NEON_VOP(rhadd_u8, neon_u8, 4) +NEON_VOP(rhadd_s16, neon_s16, 2) +NEON_VOP(rhadd_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_rhadd_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +uint32_t HELPER(neon_rhadd_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1 +NEON_VOP(hsub_s8, neon_s8, 4) +NEON_VOP(hsub_u8, neon_u8, 4) +NEON_VOP(hsub_s16, neon_s16, 2) +NEON_VOP(hsub_u16, neon_u16, 2) +#undef NEON_FN + +int32_t HELPER(neon_hsub_s32)(int32_t src1, int32_t src2) +{ + int32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2) +{ + uint32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + return dest; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 +NEON_VOP(cgt_s8, neon_s8, 4) +NEON_VOP(cgt_u8, neon_u8, 4) +NEON_VOP(cgt_s16, neon_s16, 2) +NEON_VOP(cgt_u16, neon_u16, 2) +NEON_VOP(cgt_s32, neon_s32, 1) +NEON_VOP(cgt_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 +NEON_VOP(cge_s8, neon_s8, 4) +NEON_VOP(cge_u8, neon_u8, 4) +NEON_VOP(cge_s16, neon_s16, 2) +NEON_VOP(cge_u16, neon_u16, 2) +NEON_VOP(cge_s32, neon_s32, 1) +NEON_VOP(cge_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 +NEON_VOP(min_s8, neon_s8, 4) +NEON_VOP(min_u8, neon_u8, 4) +NEON_VOP(min_s16, neon_s16, 2) +NEON_VOP(min_u16, neon_u16, 2) +NEON_VOP(min_s32, neon_s32, 1) +NEON_VOP(min_u32, neon_u32, 1) +NEON_POP(pmin_s8, neon_s8, 4) +NEON_POP(pmin_u8, neon_u8, 4) +NEON_POP(pmin_s16, neon_s16, 2) +NEON_POP(pmin_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2 +NEON_VOP(max_s8, neon_s8, 4) +NEON_VOP(max_u8, neon_u8, 4) +NEON_VOP(max_s16, neon_s16, 2) +NEON_VOP(max_u16, neon_u16, 2) +NEON_VOP(max_s32, neon_s32, 1) +NEON_VOP(max_u32, neon_u32, 1) +NEON_POP(pmax_s8, neon_s8, 4) +NEON_POP(pmax_u8, neon_u8, 4) +NEON_POP(pmax_s16, neon_s16, 2) +NEON_POP(pmax_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) \ + dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) +NEON_VOP(abd_s8, neon_s8, 4) +NEON_VOP(abd_u8, neon_u8, 4) +NEON_VOP(abd_s16, neon_s16, 2) +NEON_VOP(abd_u16, neon_u16, 2) +NEON_VOP(abd_s32, neon_s32, 1) +NEON_VOP(abd_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8 || \ + tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_u8, neon_u8, 4) +NEON_VOP(shl_u16, neon_u16, 2) +NEON_VOP(shl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64 || shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (sizeof(src1) * 8 - 1); \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_s8, neon_s8, 4) +NEON_VOP(shl_s16, neon_s16, 2) +NEON_VOP(shl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift <= -64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (sizeof(src1) * 8 - 1); \ + } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + dest++; \ + dest >>= 1; \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_s8, neon_s8, 4) +NEON_VOP(rshl_s16, neon_s16, 2) +NEON_VOP(rshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + val = 0; + } else if (shift < -64) { + val >>= 63; + } else if (shift == -63) { + val >>= 63; + val++; + val >>= 1; + } else if (shift < 0) { + val = (val + ((int64_t)1 << (-1 - shift))) >> -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8 || \ + tmp < -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> (tmp - 1); \ + } else if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(rshl_u8, neon_u8, 4) +NEON_VOP(rshl_u16, neon_u16, 2) +NEON_VOP(rshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + if (shift >= 64 || shift < 64) { + val = 0; + } else if (shift == -64) { + /* Rounding a 1-bit result just preserves that bit. */ + val >>= 63; + } if (shift < 0) { + val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift; + val >>= -shift; + } else { + val <<= shift; + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + if (src1) { \ + SET_QC(); \ + dest = ~0; \ + } else { \ + dest = 0; \ + } \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = 0; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_u8, neon_u8, 4) +NEON_VOP_ENV(qshl_u16, neon_u16, 2) +NEON_VOP_ENV(qshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift >= 64) { + if (val) { + val = ~(uint64_t)0; + SET_QC(); + } else { + val = 0; + } + } else if (shift <= -64) { + val = 0; + } else if (shift < 0) { + val >>= -shift; + } else { + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~(uint64_t)0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp >= (ssize_t)sizeof(src1) * 8) { \ + if (src1) \ + SET_QC(); \ + dest = src1 >> 31; \ + } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ + dest = src1 >> 31; \ + } else if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src2 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qshl_s8, neon_s8, 4) +NEON_VOP_ENV(qshl_s16, neon_s16, 2) +NEON_VOP_ENV(qshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + if (shift >= 64) { + if (val) { + SET_QC(); + val = (val >> 63) & ~SIGNBIT64; + } + } else if (shift <= 64) { + val >>= 63; + } else if (shift < 0) { + val >>= -shift; + } else { + int64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = (tmp >> 63) ^ ~SIGNBIT64; + } + } + return val; +} + + +/* FIXME: This is wrong. */ +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_u8, neon_u8, 4) +NEON_VOP_ENV(qrshl_u16, neon_u16, 2) +NEON_VOP_ENV(qrshl_u32, neon_u32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +{ + int8_t shift = (int8_t)shiftop; + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { \ + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = ~0; + } + } + return val; +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + if ((dest >> tmp) != src1) { \ + SET_QC(); \ + dest = src1 >> 31; \ + } \ + }} while (0) +NEON_VOP_ENV(qrshl_s8, neon_s8, 4) +NEON_VOP_ENV(qrshl_s16, neon_s16, 2) +NEON_VOP_ENV(qrshl_s32, neon_s32, 1) +#undef NEON_FN + +uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +{ + int8_t shift = (uint8_t)shiftop; + int64_t val = valop; + + if (shift < 0) { + val = (val + (1 << (-1 - shift))) >> -shift; + } else { + int64_t tmp = val;; + val <<= shift; + if ((val >> shift) != tmp) { + SET_QC(); + val = tmp >> 31; + } + } + return val; +} + +uint32_t HELPER(neon_add_u8)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80808080u; + a &= ~0x80808080u; + b &= ~0x80808080u; + return (a + b) ^ mask; +} + +uint32_t HELPER(neon_add_u16)(uint32_t a, uint32_t b) +{ + uint32_t mask; + mask = (a ^ b) & 0x80008000u; + a &= ~0x80008000u; + b &= ~0x80008000u; + return (a + b) ^ mask; +} + +#define NEON_FN(dest, src1, src2) dest = src1 + src2 +NEON_POP(padd_u8, neon_u8, 4) +NEON_POP(padd_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 - src2 +NEON_VOP(sub_u8, neon_u8, 4) +NEON_VOP(sub_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = src1 * src2 +NEON_VOP(mul_u8, neon_u8, 4) +NEON_VOP(mul_u16, neon_u16, 2) +#undef NEON_FN + +/* Polynomial multiplication is like integer multiplication except the + partial products are XORed, not added. */ +uint32_t HELPER(neon_mul_p8)(uint32_t op1, uint32_t op2) +{ + uint32_t mask; + uint32_t result; + result = 0; + while (op1) { + mask = 0; + if (op1 & 1) + mask |= 0xff; + if (op1 & (1 << 8)) + mask |= (0xff << 8); + if (op1 & (1 << 16)) + mask |= (0xff << 16); + if (op1 & (1 << 24)) + mask |= (0xff << 24); + result ^= op2 & mask; + op1 = (op1 >> 1) & 0x7f7f7f7f; + op2 = (op2 << 1) & 0xfefefefe; + } + return result; +} + +#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0 +NEON_VOP(tst_u8, neon_u8, 4) +NEON_VOP(tst_u16, neon_u16, 2) +NEON_VOP(tst_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 +NEON_VOP(ceq_u8, neon_u8, 4) +NEON_VOP(ceq_u16, neon_u16, 2) +NEON_VOP(ceq_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src +NEON_VOP1(abs_s8, neon_s8, 4) +NEON_VOP1(abs_s16, neon_s16, 2) +#undef NEON_FN + +/* Count Leading Sign/Zero Bits. */ +static inline int do_clz8(uint8_t x) +{ + int n; + for (n = 8; x; n--) + x >>= 1; + return n; +} + +static inline int do_clz16(uint16_t x) +{ + int n; + for (n = 16; x; n--) + x >>= 1; + return n; +} + +#define NEON_FN(dest, src, dummy) dest = do_clz8(src) +NEON_VOP1(clz_u8, neon_u8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16(src) +NEON_VOP1(clz_u16, neon_u16, 2) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz8((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s8, neon_s8, 4) +#undef NEON_FN + +#define NEON_FN(dest, src, dummy) dest = do_clz16((src < 0) ? ~src : src) - 1 +NEON_VOP1(cls_s16, neon_s16, 2) +#undef NEON_FN + +uint32_t HELPER(neon_cls_s32)(uint32_t x) +{ + int count; + if ((int32_t)x < 0) + x = ~x; + for (count = 32; x; count--) + x = x >> 1; + return count - 1; +} + +/* Bit count. */ +uint32_t HELPER(neon_cnt_u8)(uint32_t x) +{ + x = (x & 0x55555555) + ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f); + return x; +} + +#define NEON_QDMULH16(dest, src1, src2, round) do { \ + uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT) { \ + SET_QC(); \ + tmp = (tmp >> 31) ^ ~SIGNBIT; \ + } \ + tmp <<= 1; \ + if (round) { \ + int32_t old = tmp; \ + tmp += 1 << 15; \ + if ((int32_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT - 1; \ + } \ + } \ + dest = tmp >> 16; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s16, neon_s16, 2) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_QDMULH16 + +#define NEON_QDMULH32(dest, src1, src2, round) do { \ + uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \ + SET_QC(); \ + tmp = (tmp >> 63) ^ ~SIGNBIT64; \ + } else { \ + tmp <<= 1; \ + } \ + if (round) { \ + int64_t old = tmp; \ + tmp += (int64_t)1 << 31; \ + if ((int64_t)tmp < old) { \ + SET_QC(); \ + tmp = SIGNBIT64 - 1; \ + } \ + } \ + dest = tmp >> 32; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) +NEON_VOP_ENV(qdmulh_s32, neon_s32, 1) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) +NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1) +#undef NEON_FN +#undef NEON_QDMULH32 + +uint32_t HELPER(neon_narrow_u8)(uint64_t x) +{ + return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u) + | ((x >> 24) & 0xff000000u); +} + +uint32_t HELPER(neon_narrow_u16)(uint64_t x) +{ + return (x & 0xffffu) | ((x >> 16) & 0xffff0000u); +} + +uint32_t HELPER(neon_narrow_high_u8)(uint64_t x) +{ + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_high_u16)(uint64_t x) +{ + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_round_high_u8)(uint64_t x) +{ + x &= 0xff80ff80ff80ff80ull; + x += 0x0080008000800080ull; + return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00) + | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000); +} + +uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x) +{ + x &= 0xffff8000ffff8000ull; + x += 0x0000800000008000ull; + return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); +} + +uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x) +{ + uint16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s > 0xff) { \ + d = 0xff; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x) +{ + int16_t s; + uint8_t d; + uint32_t res = 0; +#define SAT8(n) \ + s = x >> n; \ + if (s != (int8_t)s) { \ + d = (s >> 15) ^ 0x7f; \ + SET_QC(); \ + } else { \ + d = s; \ + } \ + res |= (uint32_t)d << (n / 2); + + SAT8(0); + SAT8(16); + SAT8(32); + SAT8(48); +#undef SAT8 + return res; +} + +uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x) +{ + uint32_t high; + uint32_t low; + low = x; + if (low > 0xffff) { + low = 0xffff; + SET_QC(); + } + high = x >> 32; + if (high > 0xffff) { + high = 0xffff; + SET_QC(); + } + return low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x) +{ + int32_t low; + int32_t high; + low = x; + if (low != (int16_t)low) { + low = (low >> 31) ^ 0x7fff; + SET_QC(); + } + high = x >> 32; + if (high != (int16_t)high) { + high = (high >> 31) ^ 0x7fff; + SET_QC(); + } + return (uint16_t)low | (high << 16); +} + +uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x) +{ + if (x > 0xffffffffu) { + SET_QC(); + return 0xffffffffu; + } + return x; +} + +uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x) +{ + if ((int64_t)x != (int32_t)x) { + SET_QC(); + return (x >> 63) ^ 0x7fffffff; + } + return x; +} + +uint64_t HELPER(neon_widen_u8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint8_t)x; + tmp = (uint8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_s8)(uint32_t x) +{ + uint64_t tmp; + uint64_t ret; + ret = (uint16_t)(int8_t)x; + tmp = (uint16_t)(int8_t)(x >> 8); + ret |= tmp << 16; + tmp = (uint16_t)(int8_t)(x >> 16); + ret |= tmp << 32; + tmp = (uint16_t)(int8_t)(x >> 24); + ret |= tmp << 48; + return ret; +} + +uint64_t HELPER(neon_widen_u16)(uint32_t x) +{ + uint64_t high = (uint16_t)(x >> 16); + return ((uint16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_widen_s16)(uint32_t x) +{ + uint64_t high = (int16_t)(x >> 16); + return ((uint32_t)(int16_t)x) | (high << 32); +} + +uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000800080008000ull; + a &= ~0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ b) & 0x8000000080000000ull; + a &= ~0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a + b) ^ mask; +} + +uint64_t HELPER(neon_paddl_u16)(uint64_t a, uint64_t b) +{ + uint64_t tmp; + uint64_t tmp2; + + tmp = a & 0x0000ffff0000ffffull; + tmp += (a >> 16) & 0x0000ffff0000ffffull; + tmp2 = b & 0xffff0000ffff0000ull; + tmp2 += (b << 16) & 0xffff0000ffff0000ull; + return ( tmp & 0xffff) + | ((tmp >> 16) & 0xffff0000ull) + | ((tmp2 << 16) & 0xffff00000000ull) + | ( tmp2 & 0xffff000000000000ull); +} + +uint64_t HELPER(neon_paddl_u32)(uint64_t a, uint64_t b) +{ + uint32_t low = a + (a >> 32); + uint32_t high = b + (b >> 32); + return low + ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000800080008000ull; + a |= 0x8000800080008000ull; + b &= ~0x8000800080008000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b) +{ + uint64_t mask; + mask = (a ^ ~b) & 0x8000000080000000ull; + a |= 0x8000000080000000ull; + b &= ~0x8000000080000000ull; + return (a - b) ^ mask; +} + +uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b) +{ + uint32_t x, y; + uint32_t low, high; + + x = a; + y = b; + low = x + y; + if (((low ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + low = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + x = a >> 32; + y = b >> 32; + high = x + y; + if (((high ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) { + SET_QC(); + high = ((int32_t)x >> 31) ^ ~SIGNBIT; + } + return low | ((uint64_t)high << 32); +} + +uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b) +{ + uint64_t result; + + result = a + b; + if (((result ^ a) & SIGNBIT64) && !((a ^ b) & SIGNBIT64)) { + SET_QC(); + result = ((int64_t)a >> 63) ^ ~SIGNBIT64; + } + return result; +} + +#define DO_ABD(dest, x, y, type) do { \ + type tmp_x = x; \ + type tmp_y = y; \ + dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ + } while(0) + +uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint8_t); + DO_ABD(tmp, a >> 8, b >> 8, uint8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, uint8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, uint8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int8_t); + DO_ABD(tmp, a >> 8, b >> 8, int8_t); + result |= tmp << 16; + DO_ABD(tmp, a >> 16, b >> 16, int8_t); + result |= tmp << 32; + DO_ABD(tmp, a >> 24, b >> 24, int8_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, uint16_t); + DO_ABD(tmp, a >> 16, b >> 16, uint16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + DO_ABD(result, a, b, int16_t); + DO_ABD(tmp, a >> 16, b >> 16, int16_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, uint32_t); + return result; +} + +uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b) +{ + uint64_t result; + DO_ABD(result, a, b, int32_t); + return result; +} +#undef DO_ABD + +/* Widening multiply. Named type is the source type. */ +#define DO_MULL(dest, x, y, type1, type2) do { \ + type1 tmp_x = x; \ + type1 tmp_y = y; \ + dest = (type2)((type2)tmp_x * (type2)tmp_y); \ + } while(0) + +uint64_t HELPER(neon_mull_u8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, uint8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, uint8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, uint8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_s8)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int8_t, uint16_t); + DO_MULL(tmp, a >> 8, b >> 8, int8_t, uint16_t); + result |= tmp << 16; + DO_MULL(tmp, a >> 16, b >> 16, int8_t, uint16_t); + result |= tmp << 32; + DO_MULL(tmp, a >> 24, b >> 24, int8_t, uint16_t); + result |= tmp << 48; + return result; +} + +uint64_t HELPER(neon_mull_u16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, uint16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, uint16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_mull_s16)(uint32_t a, uint32_t b) +{ + uint64_t tmp; + uint64_t result; + + DO_MULL(result, a, b, int16_t, uint32_t); + DO_MULL(tmp, a >> 16, b >> 16, int16_t, uint32_t); + return result | (tmp << 32); +} + +uint64_t HELPER(neon_negl_u16)(uint64_t x) +{ + uint16_t tmp; + uint64_t result; + result = (uint16_t)-x; + tmp = -(x >> 16); + result |= (uint64_t)tmp << 16; + tmp = -(x >> 32); + result |= (uint64_t)tmp << 32; + tmp = -(x >> 48); + result |= (uint64_t)tmp << 48; + return result; +} + +#include +uint64_t HELPER(neon_negl_u32)(uint64_t x) +{ + uint32_t low = -x; + uint32_t high = -(x >> 32); + return low | ((uint64_t)high << 32); +} + +/* FIXME: There should be a native op for this. */ +uint64_t HELPER(neon_negl_u64)(uint64_t x) +{ + return -x; +} + +/* Saturnating sign manuipulation. */ +/* ??? Make these use NEON_VOP1 */ +#define DO_QABS8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QABS8(vec.v1); + DO_QABS8(vec.v2); + DO_QABS8(vec.v3); + DO_QABS8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QABS8 + +#define DO_QNEG8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, x); + DO_QNEG8(vec.v1); + DO_QNEG8(vec.v2); + DO_QNEG8(vec.v3); + DO_QNEG8(vec.v4); + NEON_PACK(neon_s8, x, vec); + return x; +} +#undef DO_QNEG8 + +#define DO_QABS16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QABS16(vec.v1); + DO_QABS16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QABS16 + +#define DO_QNEG16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + SET_QC(); \ + } else { \ + x = -x; \ + }} while (0) +uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, x); + DO_QNEG16(vec.v1); + DO_QNEG16(vec.v2); + NEON_PACK(neon_s16, x, vec); + return x; +} +#undef DO_QNEG16 + +uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else if ((int32_t)x < 0) { + x = -x; + } + return x; +} + +uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) +{ + if (x == SIGNBIT) { + SET_QC(); + x = ~SIGNBIT; + } else { + x = -x; + } + return x; +} + +/* NEON Float helpers. */ +uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b; +} + +uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b; +} + +uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = vfp_itos(a); + float32 f1 = vfp_itos(b); + return vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) + ? float32_sub(f0, f1, NFS) + : float32_sub(f1, f0, NFS)); +} + +uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS)); +} + +uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b) +{ + return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS)); +} + +/* Floating point comparisons produce an integer result. */ +#define NEON_VOP_FCMP(name, cmp) \ +uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \ +{ \ + if (float32_compare_quiet(vfp_itos(a), vfp_itos(b), NFS) cmp 0) \ + return ~0; \ + else \ + return 0; \ +} + +NEON_VOP_FCMP(ceq_f32, ==) +NEON_VOP_FCMP(cge_f32, >=) +NEON_VOP_FCMP(cgt_f32, >) + +uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0; +} + +uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) +{ + float32 f0 = float32_abs(vfp_itos(a)); + float32 f1 = float32_abs(vfp_itos(b)); + return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0; +} diff --git a/qemu/qemu-git/target-arm/op_addsub.h b/qemu/qemu-git/target-arm/op_addsub.h new file mode 100644 index 0000000..29f77ba --- /dev/null +++ b/qemu/qemu-git/target-arm/op_addsub.h @@ -0,0 +1,103 @@ +/* + * ARMv6 integer SIMD operations. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#ifdef ARITH_GE +#define GE_ARG , void *gep +#define DECLARE_GE uint32_t ge = 0 +#define SET_GE *(uint32_t *)gep = ge +#else +#define GE_ARG +#define DECLARE_GE do{}while(0) +#define SET_GE do{}while(0) +#endif + +#define RESULT(val, n, width) \ + res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width) + +uint32_t HELPER(glue(PFX,add16))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,add8))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD8(a, b, 0); + ADD8(a >> 8, b >> 8, 1); + ADD8(a >> 16, b >> 16, 2); + ADD8(a >> 24, b >> 24, 3); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,sub16))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,sub8))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB8(a, b, 0); + SUB8(a >> 8, b >> 8, 1); + SUB8(a >> 16, b >> 16, 2); + SUB8(a >> 24, b >> 24, 3); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(a, b, 0); + SUB16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(a, b, 0); + ADD16(a >> 16, b >> 16, 1); + SET_GE; + return res; +} + +#undef GE_ARG +#undef DECLARE_GE +#undef SET_GE +#undef RESULT + +#undef ARITH_GE +#undef PFX +#undef ADD16 +#undef SUB16 +#undef ADD8 +#undef SUB8 diff --git a/qemu/qemu-git/target-arm/op_helper.c b/qemu/qemu-git/target-arm/op_helper.c new file mode 100644 index 0000000..9b1a014 --- /dev/null +++ b/qemu/qemu-git/target-arm/op_helper.c @@ -0,0 +1,489 @@ +/* + * ARM helper routines + * + * Copyright (c) 2005-2007 CodeSourcery, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "exec.h" +#include "helpers.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + +/* thread support */ + +static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, + uint32_t rn, uint32_t maxindex) +{ + uint32_t val; + uint32_t tmp; + int index; + int shift; + uint64_t *table; + table = (uint64_t *)&env->vfp.regs[rn]; + val = 0; + for (shift = 0; shift < 32; shift += 8) { + index = (ireg >> shift) & 0xff; + if (index < maxindex) { + tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff; + val |= tmp << shift; + } else { + val |= def & (0xff << shift); + } + } + return val; +} + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); + if (unlikely(ret)) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, NULL); + } + } + raise_exception(env->exception_index); + } + env = saved_env; +} +#endif + +/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating + instructions into helper.c */ +uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) + env->QF = 1; + return res; +} + +uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { + env->QF = 1; + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint32_t HELPER(double_saturate)(int32_t val) +{ + uint32_t res; + if (val >= 0x40000000) { + res = ~SIGNBIT; + env->QF = 1; + } else if (val <= (int32_t)0xc0000000) { + res = SIGNBIT; + env->QF = 1; + } else { + res = val << 1; + } + return res; +} + +uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (res < a) { + env->QF = 1; + res = ~0; + } + return res; +} + +uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (res > a) { + env->QF = 1; + res = 0; + } + return res; +} + +/* Signed saturation. */ +static inline uint32_t do_ssat(int32_t val, int shift) +{ + int32_t top; + uint32_t mask; + + top = val >> shift; + mask = (1u << shift) - 1; + if (top > 0) { + env->QF = 1; + return mask; + } else if (top < -1) { + env->QF = 1; + return ~mask; + } + return val; +} + +/* Unsigned saturation. */ +static inline uint32_t do_usat(int32_t val, int shift) +{ + uint32_t max; + + max = (1u << shift) - 1; + if (val < 0) { + env->QF = 1; + return 0; + } else if (val > max) { + env->QF = 1; + return max; + } + return val; +} + +/* Signed saturate. */ +uint32_t HELPER(ssat)(uint32_t x, uint32_t shift) +{ + return do_ssat(x, shift); +} + +/* Dual halfword signed saturate. */ +uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_ssat((int16_t)x, shift); + res |= do_ssat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +/* Unsigned saturate. */ +uint32_t HELPER(usat)(uint32_t x, uint32_t shift) +{ + return do_usat(x, shift); +} + +/* Dual halfword unsigned saturate. */ +uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) +{ + uint32_t res; + + res = (uint16_t)do_usat((int16_t)x, shift); + res |= do_usat(((int32_t)x) >> 16, shift) << 16; + return res; +} + +void HELPER(wfi)(void) +{ + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(); +} + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(); +} + +uint32_t HELPER(cpsr_read)(void) +{ + return cpsr_read(env) & ~CPSR_EXEC; +} + +void HELPER(cpsr_write)(uint32_t val, uint32_t mask) +{ + cpsr_write(env, val, mask); +} + +/* Access to user mode registers from privileged modes. */ +uint32_t HELPER(get_user_reg)(uint32_t regno) +{ + uint32_t val; + + if (regno == 13) { + val = env->banked_r13[0]; + } else if (regno == 14) { + val = env->banked_r14[0]; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + val = env->usr_regs[regno - 8]; + } else { + val = env->regs[regno]; + } + return val; +} + +void HELPER(set_user_reg)(uint32_t regno, uint32_t val) +{ + if (regno == 13) { + env->banked_r13[0] = val; + } else if (regno == 14) { + env->banked_r14[0] = val; + } else if (regno >= 8 + && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + env->usr_regs[regno - 8] = val; + } else { + env->regs[regno] = val; + } +} + +/* ??? Flag setting arithmetic is awkward because we need to do comparisons. + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a + b; + env->NF = env->ZF = result; + env->CF = result < a; + env->VF = (a ^ b ^ -1) & (a ^ result); + return result; +} + +uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a + b; + env->CF = result < a; + } else { + result = a + b + 1; + env->CF = result <= a; + } + env->VF = (a ^ b ^ -1) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a - b; + env->NF = env->ZF = result; + env->CF = a >= b; + env->VF = (a ^ b) & (a ^ result); + return result; +} + +uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a - b - 1; + env->CF = a > b; + } else { + result = a - b; + env->CF = a >= b; + } + env->VF = (a ^ b) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +/* Similarly for variable shift instructions. */ + +uint32_t HELPER(shl)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return x << shift; +} + +uint32_t HELPER(shr)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + return 0; + return (uint32_t)x >> shift; +} + +uint32_t HELPER(sar)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) + shift = 31; + return (int32_t)x >> shift; +} + +uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = x & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (32 - shift)) & 1; + return x << shift; + } + return x; +} + +uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = (x >> 31) & 1; + else + env->CF = 0; + return 0; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return x >> shift; + } + return x; +} + +uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + env->CF = (x >> 31) & 1; + return (int32_t)x >> 31; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return (int32_t)x >> shift; + } + return x; +} + +uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) +{ + int shift1, shift; + shift1 = i & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) + env->CF = (x >> 31) & 1; + return x; + } else { + env->CF = (x >> (shift - 1)) & 1; + return ((uint32_t)x >> shift) | (x << (32 - shift)); + } +} + +uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (res < src1) { + env->QF = 1; + res = ~(uint64_t)0; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 - src2; + if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + +uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2) +{ + uint64_t res; + + if (src1 < src2) { + env->QF = 1; + res = 0; + } else { + res = src1 - src2; + } + return res; +} diff --git a/qemu/qemu-git/target-arm/translate.c b/qemu/qemu-git/target-arm/translate.c new file mode 100644 index 0000000..5cf3e06 --- /dev/null +++ b/qemu/qemu-git/target-arm/translate.c @@ -0,0 +1,9254 @@ +/* + * ARM translation + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005-2007 CodeSourcery + * Copyright (c) 2007 OpenedHand, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#include "helpers.h" +#define GEN_HELPER 1 +#include "helpers.h" + +#define ENABLE_ARCH_5J 0 +#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) +#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) +#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) +#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) + +#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0) + +/* internal defines */ +typedef struct DisasContext { + target_ulong pc; + int is_jmp; + /* Nonzero if this instruction has been conditionally skipped. */ + int condjmp; + /* The label that will be jumped to when the instruction is skipped. */ + int condlabel; + /* Thumb-2 condtional execution bits. */ + int condexec_mask; + int condexec_cond; + struct TranslationBlock *tb; + int singlestep_enabled; + int thumb; +#if !defined(CONFIG_USER_ONLY) + int user; +#endif +} DisasContext; + +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) (s->user) +#endif + +/* These instructions trap after executing, so defer them until after the + conditional executions state has been updated. */ +#define DISAS_WFI 4 +#define DISAS_SWI 5 + +static TCGv_ptr cpu_env; +/* We reuse the same 64-bit temporaries for efficiency. */ +static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; +static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_exclusive_addr; +static TCGv_i32 cpu_exclusive_val; +static TCGv_i32 cpu_exclusive_high; +#ifdef CONFIG_USER_ONLY +static TCGv_i32 cpu_exclusive_test; +static TCGv_i32 cpu_exclusive_info; +#endif + +/* FIXME: These should be removed. */ +static TCGv cpu_F0s, cpu_F1s; +static TCGv_i64 cpu_F0d, cpu_F1d; + +#include "gen-icount.h" + +static const char *regnames[] = + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; + +/* initialize TCG globals. */ +void arm_translate_init(void) +{ + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + for (i = 0; i < 16; i++) { + cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, regs[i]), + regnames[i]); + } + cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_addr), "exclusive_addr"); + cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_val), "exclusive_val"); + cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_high), "exclusive_high"); +#ifdef CONFIG_USER_ONLY + cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_test), "exclusive_test"); + cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_info), "exclusive_info"); +#endif + +#define GEN_HELPER 2 +#include "helpers.h" +} + +static int num_temps; + +/* Allocate a temporary variable. */ +static TCGv_i32 new_tmp(void) +{ + num_temps++; + return tcg_temp_new_i32(); +} + +/* Release a temporary variable. */ +static void dead_tmp(TCGv tmp) +{ + tcg_temp_free(tmp); + num_temps--; +} + +static inline TCGv load_cpu_offset(int offset) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name)) + +static inline void store_cpu_offset(TCGv var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + dead_tmp(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUState, name)) + +/* Set a variable to the value of a CPU register. */ +static void load_reg_var(DisasContext *s, TCGv var, int reg) +{ + if (reg == 15) { + uint32_t addr; + /* normaly, since we updated PC, we need only to add one insn */ + if (s->thumb) + addr = (long)s->pc + 2; + else + addr = (long)s->pc + 4; + tcg_gen_movi_i32(var, addr); + } else { + tcg_gen_mov_i32(var, cpu_R[reg]); + } +} + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv load_reg(DisasContext *s, int reg) +{ + TCGv tmp = new_tmp(); + load_reg_var(s, tmp, reg); + return tmp; +} + +/* Set a CPU register. The source must be a temporary and will be + marked as dead. */ +static void store_reg(DisasContext *s, int reg, TCGv var) +{ + if (reg == 15) { + tcg_gen_andi_i32(var, var, ~1); + s->is_jmp = DISAS_JUMP; + } + tcg_gen_mov_i32(cpu_R[reg], var); + dead_tmp(var); +} + +/* Value extensions. */ +#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) +#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) +#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) +#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) + +#define gen_sxtb16(var) gen_helper_sxtb16(var, var) +#define gen_uxtb16(var) gen_helper_uxtb16(var, var) + + +static inline void gen_set_cpsr(TCGv var, uint32_t mask) +{ + TCGv tmp_mask = tcg_const_i32(mask); + gen_helper_cpsr_write(var, tmp_mask); + tcg_temp_free_i32(tmp_mask); +} +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) + +static void gen_exception(int excp) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); + gen_helper_exception(tmp); + dead_tmp(tmp); +} + +static void gen_smul_dual(TCGv a, TCGv b) +{ + TCGv tmp1 = new_tmp(); + TCGv tmp2 = new_tmp(); + tcg_gen_ext16s_i32(tmp1, a); + tcg_gen_ext16s_i32(tmp2, b); + tcg_gen_mul_i32(tmp1, tmp1, tmp2); + dead_tmp(tmp2); + tcg_gen_sari_i32(a, a, 16); + tcg_gen_sari_i32(b, b, 16); + tcg_gen_mul_i32(b, b, a); + tcg_gen_mov_i32(a, tmp1); + dead_tmp(tmp1); +} + +/* Byteswap each halfword. */ +static void gen_rev16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_andi_i32(var, var, 0xff00ff00); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Byteswap low halfword and sign extend. */ +static void gen_revsh(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 8); + tcg_gen_andi_i32(tmp, tmp, 0x00ff); + tcg_gen_shli_i32(var, var, 8); + tcg_gen_ext8s_i32(var, var); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Unsigned bitfield extract. */ +static void gen_ubfx(TCGv var, int shift, uint32_t mask) +{ + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_andi_i32(var, var, mask); +} + +/* Signed bitfield extract. */ +static void gen_sbfx(TCGv var, int shift, int width) +{ + uint32_t signbit; + + if (shift) + tcg_gen_sari_i32(var, var, shift); + if (shift + width < 32) { + signbit = 1u << (width - 1); + tcg_gen_andi_i32(var, var, (1u << width) - 1); + tcg_gen_xori_i32(var, var, signbit); + tcg_gen_subi_i32(var, var, signbit); + } +} + +/* Bitfield insertion. Insert val into base. Clobbers base and val. */ +static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) +{ + tcg_gen_andi_i32(val, val, mask); + tcg_gen_shli_i32(val, val, shift); + tcg_gen_andi_i32(base, base, ~(mask << shift)); + tcg_gen_or_i32(dest, base, val); +} + +/* Round the top 32 bits of a 64-bit value. */ +static void gen_roundqd(TCGv a, TCGv b) +{ + tcg_gen_shri_i32(a, a, 31); + tcg_gen_add_i32(a, a, b); +} + +/* FIXME: Most targets have native widening multiplication. + It would be good to use that instead of a full wide multiply. */ +/* 32x32->64 multiply. Marks inputs as dead. */ +static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_extu_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_ext_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +/* Signed 32x32->64 multiply. */ +static void gen_imull(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + tcg_gen_ext_i32_i64(tmp2, b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + tcg_gen_trunc_i64_i32(a, tmp1); + tcg_gen_shri_i64(tmp1, tmp1, 32); + tcg_gen_trunc_i64_i32(b, tmp1); + tcg_temp_free_i64(tmp1); +} + +/* Swap low and high halfwords. */ +static void gen_swap_half(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_shli_i32(var, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. + tmp = (t0 ^ t1) & 0x8000; + t0 &= ~0x8000; + t1 &= ~0x8000; + t0 = (t0 + t1) ^ tmp; + */ + +static void gen_add16(TCGv t0, TCGv t1) +{ + TCGv tmp = new_tmp(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andi_i32(tmp, tmp, 0x8000); + tcg_gen_andi_i32(t0, t0, ~0x8000); + tcg_gen_andi_i32(t1, t1, ~0x8000); + tcg_gen_add_i32(t0, t0, t1); + tcg_gen_xor_i32(t0, t0, tmp); + dead_tmp(tmp); + dead_tmp(t1); +} + +#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF)) + +/* Set CF to the top bit of var. */ +static void gen_set_CF_bit31(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 31); + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Set N and Z flags from var. */ +static inline void gen_logic_CC(TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF)); + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF)); +} + +/* T0 += T1 + CF. */ +static void gen_adc(TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(t0, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(t0, t0, tmp); + dead_tmp(tmp); +} + +/* dest = T0 + T1 + CF. */ +static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + dead_tmp(tmp); +} + +/* dest = T0 - T1 + CF - 1. */ +static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_subi_i32(dest, dest, 1); + dead_tmp(tmp); +} + +/* FIXME: Implement this natively. */ +#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) + +static void shifter_out_im(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift == 0) { + tcg_gen_andi_i32(tmp, var, 1); + } else { + tcg_gen_shri_i32(tmp, var, shift); + if (shift != 31) + tcg_gen_andi_i32(tmp, tmp, 1); + } + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Shift by immediate. Includes special handling for shift == 0. */ +static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) +{ + switch (shiftop) { + case 0: /* LSL */ + if (shift != 0) { + if (flags) + shifter_out_im(var, 32 - shift); + tcg_gen_shli_i32(var, var, shift); + } + break; + case 1: /* LSR */ + if (shift == 0) { + if (flags) { + tcg_gen_shri_i32(var, var, 31); + gen_set_CF(var); + } + tcg_gen_movi_i32(var, 0); + } else { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_shri_i32(var, var, shift); + } + break; + case 2: /* ASR */ + if (shift == 0) + shift = 32; + if (flags) + shifter_out_im(var, shift - 1); + if (shift == 32) + shift = 31; + tcg_gen_sari_i32(var, var, shift); + break; + case 3: /* ROR/RRX */ + if (shift != 0) { + if (flags) + shifter_out_im(var, shift - 1); + tcg_gen_rotri_i32(var, var, shift); break; + } else { + TCGv tmp = load_cpu_field(CF); + if (flags) + shifter_out_im(var, 0); + tcg_gen_shri_i32(var, var, 1); + tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); + } + } +}; + +static inline void gen_arm_shift_reg(TCGv var, int shiftop, + TCGv shift, int flags) +{ + if (flags) { + switch (shiftop) { + case 0: gen_helper_shl_cc(var, var, shift); break; + case 1: gen_helper_shr_cc(var, var, shift); break; + case 2: gen_helper_sar_cc(var, var, shift); break; + case 3: gen_helper_ror_cc(var, var, shift); break; + } + } else { + switch (shiftop) { + case 0: gen_helper_shl(var, var, shift); break; + case 1: gen_helper_shr(var, var, shift); break; + case 2: gen_helper_sar(var, var, shift); break; + case 3: tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_rotr_i32(var, var, shift); break; + } + } + dead_tmp(shift); +} + +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add16)); break; \ + case 1: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 2: gen_pas_helper(glue(pfx,subaddx)); break; \ + case 3: gen_pas_helper(glue(pfx,sub16)); break; \ + case 4: gen_pas_helper(glue(pfx,add8)); break; \ + case 7: gen_pas_helper(glue(pfx,sub8)); break; \ + } +static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv_ptr tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 1: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + tcg_temp_free_ptr(tmp); + break; + case 5: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + tcg_temp_free_ptr(tmp); + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 2: + PAS_OP(q); + break; + case 3: + PAS_OP(sh); + break; + case 6: + PAS_OP(uq); + break; + case 7: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} +#undef PAS_OP + +/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */ +#define PAS_OP(pfx) \ + switch (op2) { \ + case 0: gen_pas_helper(glue(pfx,add8)); break; \ + case 1: gen_pas_helper(glue(pfx,add16)); break; \ + case 2: gen_pas_helper(glue(pfx,addsubx)); break; \ + case 4: gen_pas_helper(glue(pfx,sub8)); break; \ + case 5: gen_pas_helper(glue(pfx,sub16)); break; \ + case 6: gen_pas_helper(glue(pfx,subaddx)); break; \ + } +static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b) +{ + TCGv_ptr tmp; + + switch (op1) { +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) + case 0: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(s) + tcg_temp_free_ptr(tmp); + break; + case 4: + tmp = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); + PAS_OP(u) + tcg_temp_free_ptr(tmp); + break; +#undef gen_pas_helper +#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) + case 1: + PAS_OP(q); + break; + case 2: + PAS_OP(sh); + break; + case 5: + PAS_OP(uq); + break; + case 6: + PAS_OP(uh); + break; +#undef gen_pas_helper + } +} +#undef PAS_OP + +static void gen_test_cc(int cc, int label) +{ + TCGv tmp; + TCGv tmp2; + int inv; + + switch (cc) { + case 0: /* eq: Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 1: /* ne: !Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 2: /* cs: C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 3: /* cc: !C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 4: /* mi: N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 5: /* pl: !N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 6: /* vs: V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 7: /* vc: !V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 8: /* hi: C && !Z */ + inv = gen_new_label(); + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + gen_set_label(inv); + break; + case 9: /* ls: !C || Z */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 10: /* ge: N == V -> N ^ V == 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 11: /* lt: N != V -> N ^ V != 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 12: /* gt: !Z && N == V */ + inv = gen_new_label(); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + gen_set_label(inv); + break; + case 13: /* le: Z || N != V */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + default: + fprintf(stderr, "Bad condition code 0x%x\n", cc); + abort(); + } + dead_tmp(tmp); +} + +static const uint8_t table_logic_cc[16] = { + 1, /* and */ + 1, /* xor */ + 0, /* sub */ + 0, /* rsb */ + 0, /* add */ + 0, /* adc */ + 0, /* sbc */ + 0, /* rsc */ + 1, /* andl */ + 1, /* xorl */ + 0, /* cmp */ + 0, /* cmn */ + 1, /* orr */ + 1, /* mov */ + 1, /* bic */ + 1, /* mvn */ +}; + +/* Set PC and Thumb state from an immediate address. */ +static inline void gen_bx_im(DisasContext *s, uint32_t addr) +{ + TCGv tmp; + + s->is_jmp = DISAS_UPDATE; + if (s->thumb != (addr & 1)) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, addr & 1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb)); + dead_tmp(tmp); + } + tcg_gen_movi_i32(cpu_R[15], addr & ~1); +} + +/* Set PC and Thumb state from var. var is marked as dead. */ +static inline void gen_bx(DisasContext *s, TCGv var) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_andi_i32(cpu_R[15], var, ~1); + tcg_gen_andi_i32(var, var, 1); + store_cpu_field(var, thumb); +} + +/* Variant of store_reg which uses branch&exchange logic when storing + to r15 in ARM architecture v7 and above. The source must be a temporary + and will be marked as dead. */ +static inline void store_reg_bx(CPUState *env, DisasContext *s, + int reg, TCGv var) +{ + if (reg == 15 && ENABLE_ARCH_7) { + gen_bx(s, var); + } else { + store_reg(s, reg, var); + } +} + +static inline TCGv gen_ld8s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld8u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16s(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld16u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16u(tmp, addr, index); + return tmp; +} +static inline TCGv gen_ld32(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, index); + return tmp; +} +static inline TCGv_i64 gen_ld64(TCGv addr, int index) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp, addr, index); + return tmp; +} +static inline void gen_st8(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st8(val, addr, index); + dead_tmp(val); +} +static inline void gen_st16(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st16(val, addr, index); + dead_tmp(val); +} +static inline void gen_st32(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st32(val, addr, index); + dead_tmp(val); +} +static inline void gen_st64(TCGv_i64 val, TCGv addr, int index) +{ + tcg_gen_qemu_st64(val, addr, index); + tcg_temp_free_i64(val); +} + +static inline void gen_set_pc_im(uint32_t val) +{ + tcg_gen_movi_i32(cpu_R[15], val); +} + +/* Force a TB lookup after an instruction that changes the CPU state. */ +static inline void gen_lookup_tb(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_R[15], s->pc & ~1); + s->is_jmp = DISAS_UPDATE; +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val, rm, shift, shiftop; + TCGv offset; + + if (!(insn & (1 << 25))) { + /* immediate */ + val = insn & 0xfff; + if (!(insn & (1 << 23))) + val = -val; + if (val != 0) + tcg_gen_addi_i32(var, var, val); + } else { + /* shift/register */ + rm = (insn) & 0xf; + shift = (insn >> 7) & 0x1f; + shiftop = (insn >> 5) & 3; + offset = load_reg(s, rm); + gen_arm_shift_im(offset, shiftop, shift, 0); + if (!(insn & (1 << 23))) + tcg_gen_sub_i32(var, var, offset); + else + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, + int extra, TCGv var) +{ + int val, rm; + TCGv offset; + + if (insn & (1 << 22)) { + /* immediate */ + val = (insn & 0xf) | ((insn >> 4) & 0xf0); + if (!(insn & (1 << 23))) + val = -val; + val += extra; + if (val != 0) + tcg_gen_addi_i32(var, var, val); + } else { + /* register */ + if (extra) + tcg_gen_addi_i32(var, var, extra); + rm = (insn) & 0xf; + offset = load_reg(s, rm); + if (!(insn & (1 << 23))) + tcg_gen_sub_i32(var, var, offset); + else + tcg_gen_add_i32(var, var, offset); + dead_tmp(offset); + } +} + +#define VFP_OP2(name) \ +static inline void gen_vfp_##name(int dp) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \ +} + +VFP_OP2(add) +VFP_OP2(sub) +VFP_OP2(mul) +VFP_OP2(div) + +#undef VFP_OP2 + +static inline void gen_vfp_abs(int dp) +{ + if (dp) + gen_helper_vfp_absd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_abss(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_neg(int dp) +{ + if (dp) + gen_helper_vfp_negd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_negs(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_sqrt(int dp) +{ + if (dp) + gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env); + else + gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_cmp(int dp) +{ + if (dp) + gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_cmpe(int dp) +{ + if (dp) + gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_F1_ld0(int dp) +{ + if (dp) + tcg_gen_movi_i64(cpu_F1d, 0); + else + tcg_gen_movi_i32(cpu_F1s, 0); +} + +static inline void gen_vfp_uito(int dp) +{ + if (dp) + gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_sito(int dp) +{ + if (dp) + gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_toui(int dp) +{ + if (dp) + gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_touiz(int dp) +{ + if (dp) + gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosi(int dp) +{ + if (dp) + gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosiz(int dp) +{ + if (dp) + gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env); +} + +#define VFP_GEN_FIX(name) \ +static inline void gen_vfp_##name(int dp, int shift) \ +{ \ + TCGv tmp_shift = tcg_const_i32(shift); \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, cpu_env);\ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, cpu_env);\ + tcg_temp_free_i32(tmp_shift); \ +} +VFP_GEN_FIX(tosh) +VFP_GEN_FIX(tosl) +VFP_GEN_FIX(touh) +VFP_GEN_FIX(toul) +VFP_GEN_FIX(shto) +VFP_GEN_FIX(slto) +VFP_GEN_FIX(uhto) +VFP_GEN_FIX(ulto) +#undef VFP_GEN_FIX + +static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr) +{ + if (dp) + tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s)); + else + tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s)); +} + +static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr) +{ + if (dp) + tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s)); + else + tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s)); +} + +static inline long +vfp_reg_offset (int dp, int reg) +{ + if (dp) + return offsetof(CPUARMState, vfp.regs[reg]); + else if (reg & 1) { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} + +/* Return the offset of a 32-bit piece of a NEON register. + zero is the least significant end of the register. */ +static inline long +neon_reg_offset (int reg, int n) +{ + int sreg; + sreg = reg * 2 + n; + return vfp_reg_offset(0, sreg); +} + +static TCGv neon_load_reg(int reg, int pass) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass)); + return tmp; +} + +static void neon_store_reg(int reg, int pass, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); + dead_tmp(var); +} + +static inline void neon_load_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +static inline void neon_store_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg)); +} + +#define tcg_gen_ld_f32 tcg_gen_ld_i32 +#define tcg_gen_ld_f64 tcg_gen_ld_i64 +#define tcg_gen_st_f32 tcg_gen_st_i32 +#define tcg_gen_st_f64 tcg_gen_st_i64 + +static inline void gen_mov_F0_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_F1_vreg(int dp, int reg) +{ + if (dp) + tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg)); +} + +static inline void gen_mov_vreg_F0(int dp, int reg) +{ + if (dp) + tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); + else + tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); +} + +#define ARM_CP_RW_BIT (1 << 20) + +static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline void iwmmxt_store_reg(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg])); +} + +static inline TCGv iwmmxt_load_creg(int reg) +{ + TCGv var = new_tmp(); + tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); + return var; +} + +static inline void iwmmxt_store_creg(int reg, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg])); +} + +static inline void gen_op_iwmmxt_movq_wRn_M0(int rn) +{ + iwmmxt_store_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_movq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_M0, rn); +} + +static inline void gen_op_iwmmxt_orq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_andq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1); +} + +#define IWMMXT_OP(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV(name) \ +static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ +{ \ + iwmmxt_load_reg(cpu_V1, rn); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \ +} + +#define IWMMXT_OP_ENV_SIZE(name) \ +IWMMXT_OP_ENV(name##b) \ +IWMMXT_OP_ENV(name##w) \ +IWMMXT_OP_ENV(name##l) + +#define IWMMXT_OP_ENV1(name) \ +static inline void gen_op_iwmmxt_##name##_M0(void) \ +{ \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \ +} + +IWMMXT_OP(maddsq) +IWMMXT_OP(madduq) +IWMMXT_OP(sadb) +IWMMXT_OP(sadw) +IWMMXT_OP(mulslw) +IWMMXT_OP(mulshw) +IWMMXT_OP(mululw) +IWMMXT_OP(muluhw) +IWMMXT_OP(macsw) +IWMMXT_OP(macuw) + +IWMMXT_OP_ENV_SIZE(unpackl) +IWMMXT_OP_ENV_SIZE(unpackh) + +IWMMXT_OP_ENV1(unpacklub) +IWMMXT_OP_ENV1(unpackluw) +IWMMXT_OP_ENV1(unpacklul) +IWMMXT_OP_ENV1(unpackhub) +IWMMXT_OP_ENV1(unpackhuw) +IWMMXT_OP_ENV1(unpackhul) +IWMMXT_OP_ENV1(unpacklsb) +IWMMXT_OP_ENV1(unpacklsw) +IWMMXT_OP_ENV1(unpacklsl) +IWMMXT_OP_ENV1(unpackhsb) +IWMMXT_OP_ENV1(unpackhsw) +IWMMXT_OP_ENV1(unpackhsl) + +IWMMXT_OP_ENV_SIZE(cmpeq) +IWMMXT_OP_ENV_SIZE(cmpgtu) +IWMMXT_OP_ENV_SIZE(cmpgts) + +IWMMXT_OP_ENV_SIZE(mins) +IWMMXT_OP_ENV_SIZE(minu) +IWMMXT_OP_ENV_SIZE(maxs) +IWMMXT_OP_ENV_SIZE(maxu) + +IWMMXT_OP_ENV_SIZE(subn) +IWMMXT_OP_ENV_SIZE(addn) +IWMMXT_OP_ENV_SIZE(subu) +IWMMXT_OP_ENV_SIZE(addu) +IWMMXT_OP_ENV_SIZE(subs) +IWMMXT_OP_ENV_SIZE(adds) + +IWMMXT_OP_ENV(avgb0) +IWMMXT_OP_ENV(avgb1) +IWMMXT_OP_ENV(avgw0) +IWMMXT_OP_ENV(avgw1) + +IWMMXT_OP(msadb) + +IWMMXT_OP_ENV(packuw) +IWMMXT_OP_ENV(packul) +IWMMXT_OP_ENV(packuq) +IWMMXT_OP_ENV(packsw) +IWMMXT_OP_ENV(packsl) +IWMMXT_OP_ENV(packsq) + +static void gen_op_iwmmxt_set_mup(void) +{ + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 2); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); +} + +static void gen_op_iwmmxt_set_cup(void) +{ + TCGv tmp; + tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]); + tcg_gen_ori_i32(tmp, tmp, 1); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]); +} + +static void gen_op_iwmmxt_setpsr_nz(void) +{ + TCGv tmp = new_tmp(); + gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0); + store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]); +} + +static inline void gen_op_iwmmxt_addl_M0_wRn(int rn) +{ + iwmmxt_load_reg(cpu_V1, rn); + tcg_gen_ext32u_i64(cpu_V1, cpu_V1); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); +} + +static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest) +{ + int rd; + uint32_t offset; + TCGv tmp; + + rd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + + offset = (insn & 0xff) << ((insn >> 7) & 2); + if (insn & (1 << 24)) { + /* Pre indexed */ + if (insn & (1 << 23)) + tcg_gen_addi_i32(tmp, tmp, offset); + else + tcg_gen_addi_i32(tmp, tmp, -offset); + tcg_gen_mov_i32(dest, tmp); + if (insn & (1 << 21)) + store_reg(s, rd, tmp); + else + dead_tmp(tmp); + } else if (insn & (1 << 21)) { + /* Post indexed */ + tcg_gen_mov_i32(dest, tmp); + if (insn & (1 << 23)) + tcg_gen_addi_i32(tmp, tmp, offset); + else + tcg_gen_addi_i32(tmp, tmp, -offset); + store_reg(s, rd, tmp); + } else if (!(insn & (1 << 23))) + return 1; + return 0; +} + +static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest) +{ + int rd = (insn >> 0) & 0xf; + TCGv tmp; + + if (insn & (1 << 8)) { + if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) { + return 1; + } else { + tmp = iwmmxt_load_creg(rd); + } + } else { + tmp = new_tmp(); + iwmmxt_load_reg(cpu_V0, rd); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + } + tcg_gen_andi_i32(tmp, tmp, mask); + tcg_gen_mov_i32(dest, tmp); + dead_tmp(tmp); + return 0; +} + +/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int rd, wrd; + int rdhi, rdlo, rd0, rd1, i; + TCGv addr; + TCGv tmp, tmp2, tmp3; + + if ((insn & 0x0e000e00) == 0x0c000000) { + if ((insn & 0x0fe00ff0) == 0x0c400000) { + wrd = insn & 0xf; + rdlo = (insn >> 12) & 0xf; + rdhi = (insn >> 16) & 0xf; + if (insn & ARM_CP_RW_BIT) { /* TMRRC */ + iwmmxt_load_reg(cpu_V0, wrd); + tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0); + } else { /* TMCRR */ + tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]); + iwmmxt_store_reg(cpu_V0, wrd); + gen_op_iwmmxt_set_mup(); + } + return 0; + } + + wrd = (insn >> 12) & 0xf; + addr = new_tmp(); + if (gen_iwmmxt_address(s, insn, addr)) { + dead_tmp(addr); + return 1; + } + if (insn & ARM_CP_RW_BIT) { + if ((insn >> 28) == 0xf) { /* WLDRW wCx */ + tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s)); + iwmmxt_store_creg(wrd, tmp); + } else { + i = 1; + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WLDRD */ + tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s)); + i = 0; + } else { /* WLDRW wRd */ + tmp = gen_ld32(addr, IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WLDRH */ + tmp = gen_ld16u(addr, IS_USER(s)); + } else { /* WLDRB */ + tmp = gen_ld8u(addr, IS_USER(s)); + } + } + if (i) { + tcg_gen_extu_i32_i64(cpu_M0, tmp); + dead_tmp(tmp); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + } + } else { + if ((insn >> 28) == 0xf) { /* WSTRW wCx */ + tmp = iwmmxt_load_creg(wrd); + gen_st32(tmp, addr, IS_USER(s)); + } else { + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = new_tmp(); + if (insn & (1 << 8)) { + if (insn & (1 << 22)) { /* WSTRD */ + dead_tmp(tmp); + tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s)); + } else { /* WSTRW wRd */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st32(tmp, addr, IS_USER(s)); + } + } else { + if (insn & (1 << 22)) { /* WSTRH */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st16(tmp, addr, IS_USER(s)); + } else { /* WSTRB */ + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + gen_st8(tmp, addr, IS_USER(s)); + } + } + } + } + return 0; + } + + if ((insn & 0x0f000000) != 0x0e000000) + return 1; + + switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) { + case 0x000: /* WOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_orq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x011: /* TMCR */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + switch (wrd) { + case ARM_IWMMXT_wCID: + case ARM_IWMMXT_wCASF: + break; + case ARM_IWMMXT_wCon: + gen_op_iwmmxt_set_cup(); + /* Fall through. */ + case ARM_IWMMXT_wCSSF: + tmp = iwmmxt_load_creg(wrd); + tmp2 = load_reg(s, rd); + tcg_gen_andc_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + iwmmxt_store_creg(wrd, tmp); + break; + case ARM_IWMMXT_wCGR0: + case ARM_IWMMXT_wCGR1: + case ARM_IWMMXT_wCGR2: + case ARM_IWMMXT_wCGR3: + gen_op_iwmmxt_set_cup(); + tmp = load_reg(s, rd); + iwmmxt_store_creg(wrd, tmp); + break; + default: + return 1; + } + break; + case 0x100: /* WXOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_xorq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x111: /* TMRC */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = iwmmxt_load_creg(wrd); + store_reg(s, rd, tmp); + break; + case 0x300: /* WANDN */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tcg_gen_neg_i64(cpu_M0, cpu_M0); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x200: /* WAND */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x810: case 0xa10: /* WMADD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_maddsq_M0_wRn(rd1); + else + gen_op_iwmmxt_madduq_M0_wRn(rd1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpacklb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpacklw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackll_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpackhb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpackhw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackhl_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) + gen_op_iwmmxt_sadw_M0_wRn(rd1); + else + gen_op_iwmmxt_sadb_M0_wRn(rd1); + if (!(insn & (1 << 20))) + gen_op_iwmmxt_addl_M0_wRn(wrd); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_mulshw_M0_wRn(rd1); + else + gen_op_iwmmxt_mulslw_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_muluhw_M0_wRn(rd1); + else + gen_op_iwmmxt_mululw_M0_wRn(rd1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_macsw_M0_wRn(rd1); + else + gen_op_iwmmxt_macuw_M0_wRn(rd1); + if (!(insn & (1 << 20))) { + iwmmxt_load_reg(cpu_V1, wrd); + tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_cmpeqb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_cmpeqw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_cmpeql_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgw1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgw0_M0_wRn(rd1); + } else { + if (insn & (1 << 20)) + gen_op_iwmmxt_avgb1_M0_wRn(rd1); + else + gen_op_iwmmxt_avgb0_M0_wRn(rd1); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3)); + tcg_gen_andi_i32(tmp, tmp, 7); + iwmmxt_load_reg(cpu_V1, rd1); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */ + if (((insn >> 6) & 3) == 3) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + gen_op_iwmmxt_movq_M0_wRn(wrd); + switch ((insn >> 6) & 3) { + case 0: + tmp2 = tcg_const_i32(0xff); + tmp3 = tcg_const_i32((insn & 7) << 3); + break; + case 1: + tmp2 = tcg_const_i32(0xffff); + tmp3 = tcg_const_i32((insn & 3) << 4); + break; + case 2: + tmp2 = tcg_const_i32(0xffffffff); + tmp3 = tcg_const_i32((insn & 1) << 5); + break; + default: + TCGV_UNUSED(tmp2); + TCGV_UNUSED(tmp3); + } + gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3); + tcg_temp_free(tmp3); + tcg_temp_free(tmp2); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */ + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + if (rd == 15 || ((insn >> 22) & 3) == 3) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 0: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + if (insn & 8) { + tcg_gen_ext8s_i32(tmp, tmp); + } else { + tcg_gen_andi_i32(tmp, tmp, 0xff); + } + break; + case 1: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + if (insn & 8) { + tcg_gen_ext16s_i32(tmp, tmp); + } else { + tcg_gen_andi_i32(tmp, tmp, 0xffff); + } + break; + case 2: + tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5); + tcg_gen_trunc_i64_i32(tmp, cpu_M0); + break; + } + store_reg(s, rd, tmp); + break; + case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */ + if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + switch ((insn >> 22) & 3) { + case 0: + tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0); + break; + case 1: + tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4); + break; + case 2: + tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12); + break; + } + tcg_gen_shli_i32(tmp, tmp, 28); + gen_set_nzcv(tmp); + dead_tmp(tmp); + break; + case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */ + if (((insn >> 6) & 3) == 3) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + tmp = load_reg(s, rd); + switch ((insn >> 6) & 3) { + case 0: + gen_helper_iwmmxt_bcstb(cpu_M0, tmp); + break; + case 1: + gen_helper_iwmmxt_bcstw(cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_bcstl(cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */ + if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 4); + tcg_gen_and_i32(tmp, tmp, tmp2); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 8); + tcg_gen_and_i32(tmp, tmp, tmp2); + } + break; + case 2: + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_and_i32(tmp, tmp, tmp2); + break; + } + gen_set_nzcv(tmp); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0); + break; + case 1: + gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0); + break; + case 2: + gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */ + if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3) + return 1; + tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 4); + tcg_gen_or_i32(tmp, tmp, tmp2); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + tcg_gen_shli_i32(tmp2, tmp2, 8); + tcg_gen_or_i32(tmp, tmp, tmp2); + } + break; + case 2: + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp, tmp, tmp2); + break; + } + gen_set_nzcv(tmp); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */ + rd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3) + return 1; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 0: + gen_helper_iwmmxt_msbb(tmp, cpu_M0); + break; + case 1: + gen_helper_iwmmxt_msbw(tmp, cpu_M0); + break; + case 2: + gen_helper_iwmmxt_msbl(tmp, cpu_M0); + break; + } + store_reg(s, rd, tmp); + break; + case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */ + case 0x906: case 0xb06: case 0xd06: case 0xf06: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */ + case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsb_M0(); + else + gen_op_iwmmxt_unpacklub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsw_M0(); + else + gen_op_iwmmxt_unpackluw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsl_M0(); + else + gen_op_iwmmxt_unpacklul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */ + case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsb_M0(); + else + gen_op_iwmmxt_unpackhub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsw_M0(); + else + gen_op_iwmmxt_unpackhuw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsl_M0(); + else + gen_op_iwmmxt_unpackhul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */ + case 0x214: case 0x614: case 0xa14: case 0xe14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */ + case 0x014: case 0x414: case 0x814: case 0xc14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */ + case 0x114: case 0x514: case 0x914: case 0xd14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + if (gen_iwmmxt_shift(insn, 0xff, tmp)) { + dead_tmp(tmp); + return 1; + } + switch ((insn >> 22) & 3) { + case 1: + gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */ + case 0x314: case 0x714: case 0xb14: case 0xf14: + if (((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = new_tmp(); + switch ((insn >> 22) & 3) { + case 1: + if (gen_iwmmxt_shift(insn, 0xf, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 2: + if (gen_iwmmxt_shift(insn, 0x1f, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp); + break; + case 3: + if (gen_iwmmxt_shift(insn, 0x3f, tmp)) { + dead_tmp(tmp); + return 1; + } + gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp); + break; + } + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */ + case 0x916: case 0xb16: case 0xd16: case 0xf16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsb_M0_wRn(rd1); + else + gen_op_iwmmxt_minub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsw_M0_wRn(rd1); + else + gen_op_iwmmxt_minuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsl_M0_wRn(rd1); + else + gen_op_iwmmxt_minul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */ + case 0x816: case 0xa16: case 0xc16: case 0xe16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsb_M0_wRn(rd1); + else + gen_op_iwmmxt_maxub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsw_M0_wRn(rd1); + else + gen_op_iwmmxt_maxuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsl_M0_wRn(rd1); + else + gen_op_iwmmxt_maxul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */ + case 0x402: case 0x502: case 0x602: case 0x702: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = tcg_const_i32((insn >> 20) & 3); + iwmmxt_load_reg(cpu_V1, rd1); + gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp); + tcg_temp_free(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */ + case 0x41a: case 0x51a: case 0x61a: case 0x71a: + case 0x81a: case 0x91a: case 0xa1a: case 0xb1a: + case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_subnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_subub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_subsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_subnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_subuw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_subsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_subnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_subul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_subsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */ + case 0x41e: case 0x51e: case 0x61e: case 0x71e: + case 0x81e: case 0x91e: case 0xa1e: case 0xb1e: + case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); + gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp); + tcg_temp_free(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */ + case 0x418: case 0x518: case 0x618: case 0x718: + case 0x818: case 0x918: case 0xa18: case 0xb18: + case 0xc18: case 0xd18: case 0xe18: case 0xf18: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_addnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_addub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_addsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_addnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_adduw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_addsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_addnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_addul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_addsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */ + case 0x408: case 0x508: case 0x608: case 0x708: + case 0x808: case 0x908: case 0xa08: case 0xb08: + case 0xc08: case 0xd08: case 0xe08: case 0xf08: + if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0) + return 1; + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsw_M0_wRn(rd1); + else + gen_op_iwmmxt_packuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsl_M0_wRn(rd1); + else + gen_op_iwmmxt_packul_M0_wRn(rd1); + break; + case 3: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsq_M0_wRn(rd1); + else + gen_op_iwmmxt_packuq_M0_wRn(rd1); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x201: case 0x203: case 0x205: case 0x207: + case 0x209: case 0x20b: case 0x20d: case 0x20f: + case 0x211: case 0x213: case 0x215: case 0x217: + case 0x219: case 0x21b: case 0x21d: case 0x21f: + wrd = (insn >> 5) & 0xf; + rd0 = (insn >> 12) & 0xf; + rd1 = (insn >> 0) & 0xf; + if (rd0 == 0xf || rd1 == 0xf) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + tmp = load_reg(s, rd0); + tmp2 = load_reg(s, rd1); + switch ((insn >> 16) & 0xf) { + case 0x0: /* TMIA */ + gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0x8: /* TMIAPH */ + gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */ + if (insn & (1 << 16)) + tcg_gen_shri_i32(tmp, tmp, 16); + if (insn & (1 << 17)) + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2); + break; + default: + dead_tmp(tmp2); + dead_tmp(tmp); + return 1; + } + dead_tmp(tmp2); + dead_tmp(tmp); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + default: + return 1; + } + + return 0; +} + +/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int acc, rd0, rd1, rdhi, rdlo; + TCGv tmp, tmp2; + + if ((insn & 0x0ff00f10) == 0x0e200010) { + /* Multiply with Internal Accumulate Format */ + rd0 = (insn >> 12) & 0xf; + rd1 = insn & 0xf; + acc = (insn >> 5) & 7; + + if (acc != 0) + return 1; + + tmp = load_reg(s, rd0); + tmp2 = load_reg(s, rd1); + switch ((insn >> 16) & 0xf) { + case 0x0: /* MIA */ + gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0x8: /* MIAPH */ + gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2); + break; + case 0xc: /* MIABB */ + case 0xd: /* MIABT */ + case 0xe: /* MIATB */ + case 0xf: /* MIATT */ + if (insn & (1 << 16)) + tcg_gen_shri_i32(tmp, tmp, 16); + if (insn & (1 << 17)) + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2); + break; + default: + return 1; + } + dead_tmp(tmp2); + dead_tmp(tmp); + + gen_op_iwmmxt_movq_wRn_M0(acc); + return 0; + } + + if ((insn & 0x0fe00ff8) == 0x0c400000) { + /* Internal Accumulator Access Format */ + rdhi = (insn >> 16) & 0xf; + rdlo = (insn >> 12) & 0xf; + acc = insn & 7; + + if (acc != 0) + return 1; + + if (insn & ARM_CP_RW_BIT) { /* MRA */ + iwmmxt_load_reg(cpu_V0, acc); + tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0); + tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1); + } else { /* MAR */ + tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]); + iwmmxt_store_reg(cpu_V0, acc); + } + return 0; + } + + return 1; +} + +/* Disassemble system coprocessor instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp, tmp2; + uint32_t rd = (insn >> 12) & 0xf; + uint32_t cp = (insn >> 8) & 0xf; + if (IS_USER(s)) { + return 1; + } + + if (insn & ARM_CP_RW_BIT) { + if (!env->cp[cp].cp_read) + return 1; + gen_set_pc_im(s->pc); + tmp = new_tmp(); + tmp2 = tcg_const_i32(insn); + gen_helper_get_cp(tmp, cpu_env, tmp2); + tcg_temp_free(tmp2); + store_reg(s, rd, tmp); + } else { + if (!env->cp[cp].cp_write) + return 1; + gen_set_pc_im(s->pc); + tmp = load_reg(s, rd); + tmp2 = tcg_const_i32(insn); + gen_helper_set_cp(cpu_env, tmp2, tmp); + tcg_temp_free(tmp2); + dead_tmp(tmp); + } + return 0; +} + +static int cp15_user_ok(uint32_t insn) +{ + int cpn = (insn >> 16) & 0xf; + int cpm = insn & 0xf; + int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); + + if (cpn == 13 && cpm == 0) { + /* TLS register. */ + if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) + return 1; + } + if (cpn == 7) { + /* ISB, DSB, DMB. */ + if ((cpm == 5 && op == 4) + || (cpm == 10 && (op == 4 || op == 5))) + return 1; + } + return 0; +} + +/* Disassemble system coprocessor (cp15) instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + uint32_t rd; + TCGv tmp, tmp2; + + /* M profile cores use memory mapped registers instead of cp15. */ + if (arm_feature(env, ARM_FEATURE_M)) + return 1; + + if ((insn & (1 << 25)) == 0) { + if (insn & (1 << 20)) { + /* mrrc */ + return 1; + } + /* mcrr. Used for block cache operations, so implement as no-op. */ + return 0; + } + if ((insn & (1 << 4)) == 0) { + /* cdp */ + return 1; + } + if (IS_USER(s) && !cp15_user_ok(insn)) { + return 1; + } + if ((insn & 0x0fff0fff) == 0x0e070f90 + || (insn & 0x0fff0fff) == 0x0e070f58) { + /* Wait for interrupt. */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_WFI; + return 0; + } + rd = (insn >> 12) & 0xf; + tmp2 = tcg_const_i32(insn); + if (insn & ARM_CP_RW_BIT) { + tmp = new_tmp(); + gen_helper_get_cp15(tmp, cpu_env, tmp2); + /* If the destination register is r15 then sets condition codes. */ + if (rd != 15) + store_reg(s, rd, tmp); + else + dead_tmp(tmp); + } else { + tmp = load_reg(s, rd); + gen_helper_set_cp15(cpu_env, tmp2, tmp); + dead_tmp(tmp); + /* Normally we would always end the TB here, but Linux + * arch/arm/mach-pxa/sleep.S expects two instructions following + * an MMU enable to execute from cache. Imitate this behaviour. */ + if (!arm_feature(env, ARM_FEATURE_XSCALE) || + (insn & 0x0fff0fff) != 0x0e010f10) + gen_lookup_tb(s); + } + tcg_temp_free_i32(tmp2); + return 0; +} + +#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) +#define VFP_SREG(insn, bigbit, smallbit) \ + ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) +#define VFP_DREG(reg, insn, bigbit, smallbit) do { \ + if (arm_feature(env, ARM_FEATURE_VFP3)) { \ + reg = (((insn) >> (bigbit)) & 0x0f) \ + | (((insn) >> ((smallbit) - 4)) & 0x10); \ + } else { \ + if (insn & (1 << (smallbit))) \ + return 1; \ + reg = ((insn) >> (bigbit)) & 0x0f; \ + }} while (0) + +#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22) +#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22) +#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7) +#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) +#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) +#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) + +/* Move between integer and VFP cores. */ +static TCGv gen_vfp_mrs(void) +{ + TCGv tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_F0s); + return tmp; +} + +static void gen_vfp_msr(TCGv tmp) +{ + tcg_gen_mov_i32(cpu_F0s, tmp); + dead_tmp(tmp); +} + +static inline int +vfp_enabled(CPUState * env) +{ + return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0); +} + +static void gen_neon_dup_u8(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift) + tcg_gen_shri_i32(var, var, shift); + tcg_gen_ext8u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 8); + tcg_gen_or_i32(var, var, tmp); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_low16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_ext16u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +static void gen_neon_dup_high16(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_andi_i32(var, var, 0xffff0000); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); +} + +/* Disassemble a VFP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; + int dp, veclen; + TCGv addr; + TCGv tmp; + TCGv tmp2; + + if (!arm_feature(env, ARM_FEATURE_VFP)) + return 1; + + if (!vfp_enabled(env)) { + /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */ + if ((insn & 0x0fe00fff) != 0x0ee00a10) + return 1; + rn = (insn >> 16) & 0xf; + if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC + && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) + return 1; + } + dp = ((insn & 0xf00) == 0xb00); + switch ((insn >> 24) & 0xf) { + case 0xe: + if (insn & (1 << 4)) { + /* single register transfer */ + rd = (insn >> 12) & 0xf; + if (dp) { + int size; + int pass; + + VFP_DREG_N(rn, insn); + if (insn & 0xf) + return 1; + if (insn & 0x00c00060 + && !arm_feature(env, ARM_FEATURE_NEON)) + return 1; + + pass = (insn >> 21) & 1; + if (insn & (1 << 22)) { + size = 0; + offset = ((insn >> 5) & 3) * 8; + } else if (insn & (1 << 5)) { + size = 1; + offset = (insn & (1 << 6)) ? 16 : 0; + } else { + size = 2; + offset = 0; + } + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + tmp = neon_load_reg(rn, pass); + switch (size) { + case 0: + if (offset) + tcg_gen_shri_i32(tmp, tmp, offset); + if (insn & (1 << 23)) + gen_uxtb(tmp); + else + gen_sxtb(tmp); + break; + case 1: + if (insn & (1 << 23)) { + if (offset) { + tcg_gen_shri_i32(tmp, tmp, 16); + } else { + gen_uxth(tmp); + } + } else { + if (offset) { + tcg_gen_sari_i32(tmp, tmp, 16); + } else { + gen_sxth(tmp); + } + } + break; + case 2: + break; + } + store_reg(s, rd, tmp); + } else { + /* arm->vfp */ + tmp = load_reg(s, rd); + if (insn & (1 << 23)) { + /* VDUP */ + if (size == 0) { + gen_neon_dup_u8(tmp, 0); + } else if (size == 1) { + gen_neon_dup_low16(tmp); + } + for (n = 0; n <= pass * 2; n++) { + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rn, n, tmp2); + } + neon_store_reg(rn, n, tmp); + } else { + /* VMOV */ + switch (size) { + case 0: + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xff); + dead_tmp(tmp2); + break; + case 1: + tmp2 = neon_load_reg(rn, pass); + gen_bfi(tmp, tmp2, tmp, offset, 0xffff); + dead_tmp(tmp2); + break; + case 2: + break; + } + neon_store_reg(rn, pass, tmp); + } + } + } else { /* !dp */ + if ((insn & 0x6f) != 0x00) + return 1; + rn = VFP_SREG_N(insn); + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + if (insn & (1 << 21)) { + /* system register */ + rn >>= 1; + + switch (rn) { + case ARM_VFP_FPSID: + /* VFP2 allows access to FSID from userspace. + VFP3 restricts all id registers to privileged + accesses. */ + if (IS_USER(s) + && arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + /* Not present in VFP3. */ + if (IS_USER(s) + || arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + case ARM_VFP_FPSCR: + if (rd == 15) { + tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); + tcg_gen_andi_i32(tmp, tmp, 0xf0000000); + } else { + tmp = new_tmp(); + gen_helper_vfp_get_fpscr(tmp, cpu_env); + } + break; + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: + if (IS_USER(s) + || !arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + tmp = load_cpu_field(vfp.xregs[rn]); + break; + default: + return 1; + } + } else { + gen_mov_F0_vreg(0, rn); + tmp = gen_vfp_mrs(); + } + if (rd == 15) { + /* Set the 4 flag bits in the CPSR. */ + gen_set_nzcv(tmp); + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + } + } else { + /* arm->vfp */ + tmp = load_reg(s, rd); + if (insn & (1 << 21)) { + rn >>= 1; + /* system register */ + switch (rn) { + case ARM_VFP_FPSID: + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: + /* Writes are ignored. */ + break; + case ARM_VFP_FPSCR: + gen_helper_vfp_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); + gen_lookup_tb(s); + break; + case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; + /* TODO: VFP subarchitecture support. + * For now, keep the EN bit only */ + tcg_gen_andi_i32(tmp, tmp, 1 << 30); + store_cpu_field(tmp, vfp.xregs[rn]); + gen_lookup_tb(s); + break; + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + store_cpu_field(tmp, vfp.xregs[rn]); + break; + default: + return 1; + } + } else { + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rn); + } + } + } + } else { + /* data processing */ + /* The opcode is in bits 23, 21, 20 and 6. */ + op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1); + if (dp) { + if (op == 15) { + /* rn is opcode */ + rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + } else { + /* rn is register number */ + VFP_DREG_N(rn, insn); + } + + if (op == 15 && (rn == 15 || rn > 17)) { + /* Integer or single precision destination. */ + rd = VFP_SREG_D(insn); + } else { + VFP_DREG_D(rd, insn); + } + + if (op == 15 && (rn == 16 || rn == 17)) { + /* Integer source. */ + rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + } else { + VFP_DREG_M(rm, insn); + } + } else { + rn = VFP_SREG_N(insn); + if (op == 15 && rn == 15) { + /* Double precision destination. */ + VFP_DREG_D(rd, insn); + } else { + rd = VFP_SREG_D(insn); + } + rm = VFP_SREG_M(insn); + } + + veclen = env->vfp.vec_len; + if (op == 15 && rn > 3) + veclen = 0; + + /* Shut up compiler warnings. */ + delta_m = 0; + delta_d = 0; + bank_mask = 0; + + if (veclen > 0) { + if (dp) + bank_mask = 0xc; + else + bank_mask = 0x18; + + /* Figure out what type of vector operation this is. */ + if ((rd & bank_mask) == 0) { + /* scalar */ + veclen = 0; + } else { + if (dp) + delta_d = (env->vfp.vec_stride >> 1) + 1; + else + delta_d = env->vfp.vec_stride + 1; + + if ((rm & bank_mask) == 0) { + /* mixed scalar/vector */ + delta_m = 0; + } else { + /* vector */ + delta_m = delta_d; + } + } + } + + /* Load the initial operands. */ + if (op == 15) { + switch (rn) { + case 16: + case 17: + /* Integer source */ + gen_mov_F0_vreg(0, rm); + break; + case 8: + case 9: + /* Compare */ + gen_mov_F0_vreg(dp, rd); + gen_mov_F1_vreg(dp, rm); + break; + case 10: + case 11: + /* Compare with zero */ + gen_mov_F0_vreg(dp, rd); + gen_vfp_F1_ld0(dp); + break; + case 20: + case 21: + case 22: + case 23: + case 28: + case 29: + case 30: + case 31: + /* Source and destination the same. */ + gen_mov_F0_vreg(dp, rd); + break; + default: + /* One source operand. */ + gen_mov_F0_vreg(dp, rm); + break; + } + } else { + /* Two source operands. */ + gen_mov_F0_vreg(dp, rn); + gen_mov_F1_vreg(dp, rm); + } + + for (;;) { + /* Perform the calculation. */ + switch (op) { + case 0: /* mac: fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 1: /* nmac: fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 2: /* msc: -fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); + break; + case 3: /* nmsc: -fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); + break; + case 4: /* mul: fn * fm */ + gen_vfp_mul(dp); + break; + case 5: /* nmul: -(fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + break; + case 6: /* add: fn + fm */ + gen_vfp_add(dp); + break; + case 7: /* sub: fn - fm */ + gen_vfp_sub(dp); + break; + case 8: /* div: fn / fm */ + gen_vfp_div(dp); + break; + case 14: /* fconst */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + + n = (insn << 12) & 0x80000000; + i = ((insn >> 12) & 0x70) | (insn & 0xf); + if (dp) { + if (i & 0x40) + i |= 0x3f80; + else + i |= 0x4000; + n |= i << 16; + tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32); + } else { + if (i & 0x40) + i |= 0x780; + else + i |= 0x800; + n |= i << 19; + tcg_gen_movi_i32(cpu_F0s, n); + } + break; + case 15: /* extension space */ + switch (rn) { + case 0: /* cpy */ + /* no-op */ + break; + case 1: /* abs */ + gen_vfp_abs(dp); + break; + case 2: /* neg */ + gen_vfp_neg(dp); + break; + case 3: /* sqrt */ + gen_vfp_sqrt(dp); + break; + case 4: /* vcvtb.f32.f16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = gen_vfp_mrs(); + tcg_gen_ext16u_i32(tmp, tmp); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); + dead_tmp(tmp); + break; + case 5: /* vcvtt.f32.f16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = gen_vfp_mrs(); + tcg_gen_shri_i32(tmp, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env); + dead_tmp(tmp); + break; + case 6: /* vcvtb.f16.f32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + gen_mov_F0_vreg(0, rd); + tmp2 = gen_vfp_mrs(); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + gen_vfp_msr(tmp); + break; + case 7: /* vcvtt.f16.f32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp, tmp, 16); + gen_mov_F0_vreg(0, rd); + tmp2 = gen_vfp_mrs(); + tcg_gen_ext16u_i32(tmp2, tmp2); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + gen_vfp_msr(tmp); + break; + case 8: /* cmp */ + gen_vfp_cmp(dp); + break; + case 9: /* cmpe */ + gen_vfp_cmpe(dp); + break; + case 10: /* cmpz */ + gen_vfp_cmp(dp); + break; + case 11: /* cmpez */ + gen_vfp_F1_ld0(dp); + gen_vfp_cmpe(dp); + break; + case 15: /* single<->double conversion */ + if (dp) + gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); + break; + case 16: /* fuito */ + gen_vfp_uito(dp); + break; + case 17: /* fsito */ + gen_vfp_sito(dp); + break; + case 20: /* fshto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_shto(dp, 16 - rm); + break; + case 21: /* fslto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_slto(dp, 32 - rm); + break; + case 22: /* fuhto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_uhto(dp, 16 - rm); + break; + case 23: /* fulto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_ulto(dp, 32 - rm); + break; + case 24: /* ftoui */ + gen_vfp_toui(dp); + break; + case 25: /* ftouiz */ + gen_vfp_touiz(dp); + break; + case 26: /* ftosi */ + gen_vfp_tosi(dp); + break; + case 27: /* ftosiz */ + gen_vfp_tosiz(dp); + break; + case 28: /* ftosh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosh(dp, 16 - rm); + break; + case 29: /* ftosl */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosl(dp, 32 - rm); + break; + case 30: /* ftouh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_touh(dp, 16 - rm); + break; + case 31: /* ftoul */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_toul(dp, 32 - rm); + break; + default: /* undefined */ + printf ("rn:%d\n", rn); + return 1; + } + break; + default: /* undefined */ + printf ("op:%d\n", op); + return 1; + } + + /* Write back the result. */ + if (op == 15 && (rn >= 8 && rn <= 11)) + ; /* Comparison, do nothing. */ + else if (op == 15 && rn > 17) + /* Integer result. */ + gen_mov_vreg_F0(0, rd); + else if (op == 15 && rn == 15) + /* conversion */ + gen_mov_vreg_F0(!dp, rd); + else + gen_mov_vreg_F0(dp, rd); + + /* break out of the loop if we have finished */ + if (veclen == 0) + break; + + if (op == 15 && delta_m == 0) { + /* single source one-many */ + while (veclen--) { + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + gen_mov_vreg_F0(dp, rd); + } + break; + } + /* Setup the next operands. */ + veclen--; + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + + if (op == 15) { + /* One source operand. */ + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F0_vreg(dp, rm); + } else { + /* Two source operands. */ + rn = ((rn + delta_d) & (bank_mask - 1)) + | (rn & bank_mask); + gen_mov_F0_vreg(dp, rn); + if (delta_m) { + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F1_vreg(dp, rm); + } + } + } + } + break; + case 0xc: + case 0xd: + if (dp && (insn & 0x03e00000) == 0x00400000) { + /* two-register transfer */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (dp) { + VFP_DREG_M(rm, insn); + } else { + rm = VFP_SREG_M(insn); + } + + if (insn & ARM_CP_RW_BIT) { + /* vfp->arm */ + if (dp) { + gen_mov_F0_vreg(0, rm * 2); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + gen_mov_F0_vreg(0, rm * 2 + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); + } else { + gen_mov_F0_vreg(0, rm); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); + gen_mov_F0_vreg(0, rm + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + } + } else { + /* arm->vfp */ + if (dp) { + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2 + 1); + } else { + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm + 1); + } + } + } else { + /* Load/store */ + rn = (insn >> 16) & 0xf; + if (dp) + VFP_DREG_D(rd, insn); + else + rd = VFP_SREG_D(insn); + if (s->thumb && rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } + if ((insn & 0x01200000) == 0x01000000) { + /* Single load/store */ + offset = (insn & 0xff) << 2; + if ((insn & (1 << 23)) == 0) + offset = -offset; + tcg_gen_addi_i32(addr, addr, offset); + if (insn & (1 << 20)) { + gen_vfp_ld(s, dp, addr); + gen_mov_vreg_F0(dp, rd); + } else { + gen_mov_F0_vreg(dp, rd); + gen_vfp_st(s, dp, addr); + } + dead_tmp(addr); + } else { + /* load/store multiple */ + if (dp) + n = (insn >> 1) & 0x7f; + else + n = insn & 0xff; + + if (insn & (1 << 24)) /* pre-decrement */ + tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2)); + + if (dp) + offset = 8; + else + offset = 4; + for (i = 0; i < n; i++) { + if (insn & ARM_CP_RW_BIT) { + /* load */ + gen_vfp_ld(s, dp, addr); + gen_mov_vreg_F0(dp, rd + i); + } else { + /* store */ + gen_mov_F0_vreg(dp, rd + i); + gen_vfp_st(s, dp, addr); + } + tcg_gen_addi_i32(addr, addr, offset); + } + if (insn & (1 << 21)) { + /* writeback */ + if (insn & (1 << 24)) + offset = -offset * n; + else if (dp && (insn & 1)) + offset = 4; + else + offset = 0; + + if (offset != 0) + tcg_gen_addi_i32(addr, addr, offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + } + break; + default: + /* Should never happen. */ + return 1; + } + return 0; +} + +static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + gen_set_pc_im(dest); + tcg_gen_exit_tb((long)tb + n); + } else { + gen_set_pc_im(dest); + tcg_gen_exit_tb(0); + } +} + +static inline void gen_jmp (DisasContext *s, uint32_t dest) +{ + if (unlikely(s->singlestep_enabled)) { + /* An indirect jump so that we still trigger the debug exception. */ + if (s->thumb) + dest |= 1; + gen_bx_im(s, dest); + } else { + gen_goto_tb(s, 0, dest); + s->is_jmp = DISAS_TB_JUMP; + } +} + +static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y) +{ + if (x) + tcg_gen_sari_i32(t0, t0, 16); + else + gen_sxth(t0); + if (y) + tcg_gen_sari_i32(t1, t1, 16); + else + gen_sxth(t1); + tcg_gen_mul_i32(t0, t0, t1); +} + +/* Return the mask of PSR bits set by a MSR instruction. */ +static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { + uint32_t mask; + + mask = 0; + if (flags & (1 << 0)) + mask |= 0xff; + if (flags & (1 << 1)) + mask |= 0xff00; + if (flags & (1 << 2)) + mask |= 0xff0000; + if (flags & (1 << 3)) + mask |= 0xff000000; + + /* Mask out undefined bits. */ + mask &= ~CPSR_RESERVED; + if (!arm_feature(env, ARM_FEATURE_V6)) + mask &= ~(CPSR_E | CPSR_GE); + if (!arm_feature(env, ARM_FEATURE_THUMB2)) + mask &= ~CPSR_IT; + /* Mask out execution state bits. */ + if (!spsr) + mask &= ~CPSR_EXEC; + /* Mask out privileged bits. */ + if (IS_USER(s)) + mask &= CPSR_USER; + return mask; +} + +/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ +static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0) +{ + TCGv tmp; + if (spsr) { + /* ??? This is also undefined in system mode. */ + if (IS_USER(s)) + return 1; + + tmp = load_cpu_field(spsr); + tcg_gen_andi_i32(tmp, tmp, ~mask); + tcg_gen_andi_i32(t0, t0, mask); + tcg_gen_or_i32(tmp, tmp, t0); + store_cpu_field(tmp, spsr); + } else { + gen_set_cpsr(t0, mask); + } + dead_tmp(t0); + gen_lookup_tb(s); + return 0; +} + +/* Returns nonzero if access to the PSR is not permitted. */ +static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + return gen_set_psr(s, mask, spsr, tmp); +} + +/* Generate an old-style exception return. Marks pc as dead. */ +static void gen_exception_return(DisasContext *s, TCGv pc) +{ + TCGv tmp; + store_reg(s, 15, pc); + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; +} + +/* Generate a v6 exception return. Marks both values as dead. */ +static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr) +{ + gen_set_cpsr(cpsr, 0xffffffff); + dead_tmp(cpsr); + store_reg(s, 15, pc); + s->is_jmp = DISAS_UPDATE; +} + +static inline void +gen_set_condexec (DisasContext *s) +{ + if (s->condexec_mask) { + uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_cpu_field(tmp, condexec_bits); + } +} + +static void gen_nop_hint(DisasContext *s, int val) +{ + switch (val) { + case 3: /* wfi */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_WFI; + break; + case 2: /* wfe */ + case 4: /* sev */ + /* TODO: Implement SEV and WFE. May help SMP performance. */ + default: /* nop */ + break; + } +} + +#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 + +static inline int gen_neon_add(int size, TCGv t0, TCGv t1) +{ + switch (size) { + case 0: gen_helper_neon_add_u8(t0, t0, t1); break; + case 1: gen_helper_neon_add_u16(t0, t0, t1); break; + case 2: tcg_gen_add_i32(t0, t0, t1); break; + default: return 1; + } + return 0; +} + +static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1) +{ + switch (size) { + case 0: gen_helper_neon_sub_u8(t0, t1, t0); break; + case 1: gen_helper_neon_sub_u16(t0, t1, t0); break; + case 2: tcg_gen_sub_i32(t0, t1, t0); break; + default: return; + } +} + +/* 32-bit pairwise ops end up the same as the elementwise versions. */ +#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32 +#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32 +#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32 +#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32 + +/* FIXME: This is wrong. They set the wrong overflow bit. */ +#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c) +#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c) +#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c) +#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c) + +#define GEN_NEON_INTEGER_OP_ENV(name) do { \ + switch ((size << 1) | u) { \ + case 0: \ + gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \ + break; \ + default: return 1; \ + }} while (0) + +#define GEN_NEON_INTEGER_OP(name) do { \ + switch ((size << 1) | u) { \ + case 0: \ + gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \ + break; \ + case 1: \ + gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \ + break; \ + case 2: \ + gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \ + break; \ + case 3: \ + gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \ + break; \ + case 4: \ + gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \ + break; \ + case 5: \ + gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \ + break; \ + default: return 1; \ + }} while (0) + +static TCGv neon_load_scratch(int scratch) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); + return tmp; +} + +static void neon_store_scratch(int scratch, TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); + dead_tmp(var); +} + +static inline TCGv neon_get_scalar(int size, int reg) +{ + TCGv tmp; + if (size == 1) { + tmp = neon_load_reg(reg >> 1, reg & 1); + } else { + tmp = neon_load_reg(reg >> 2, (reg >> 1) & 1); + if (reg & 1) { + gen_neon_dup_low16(tmp); + } else { + gen_neon_dup_high16(tmp); + } + } + return tmp; +} + +static void gen_neon_unzip_u8(TCGv t0, TCGv t1) +{ + TCGv rd, rm, tmp; + + rd = new_tmp(); + rm = new_tmp(); + tmp = new_tmp(); + + tcg_gen_andi_i32(rd, t0, 0xff); + tcg_gen_shri_i32(tmp, t0, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff000000); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(rm, t0, 8); + tcg_gen_andi_i32(rm, rm, 0xff); + tcg_gen_shri_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_andi_i32(tmp, t1, 0xff000000); + tcg_gen_or_i32(t1, rm, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rm); + dead_tmp(rd); +} + +static void gen_neon_zip_u8(TCGv t0, TCGv t1) +{ + TCGv rd, rm, tmp; + + rd = new_tmp(); + rm = new_tmp(); + tmp = new_tmp(); + + tcg_gen_andi_i32(rd, t0, 0xff); + tcg_gen_shli_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shli_i32(tmp, t1, 24); + tcg_gen_andi_i32(tmp, tmp, 0xff000000); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_andi_i32(rm, t1, 0xff000000); + tcg_gen_shri_i32(tmp, t0, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff0000); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shri_i32(tmp, t1, 8); + tcg_gen_andi_i32(tmp, tmp, 0xff00); + tcg_gen_or_i32(rm, rm, tmp); + tcg_gen_shri_i32(tmp, t0, 16); + tcg_gen_andi_i32(tmp, tmp, 0xff); + tcg_gen_or_i32(t1, rm, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rm); + dead_tmp(rd); +} + +static void gen_neon_zip_u16(TCGv t0, TCGv t1) +{ + TCGv tmp, tmp2; + + tmp = new_tmp(); + tmp2 = new_tmp(); + + tcg_gen_andi_i32(tmp, t0, 0xffff); + tcg_gen_shli_i32(tmp2, t1, 16); + tcg_gen_or_i32(tmp, tmp, tmp2); + tcg_gen_andi_i32(t1, t1, 0xffff0000); + tcg_gen_shri_i32(tmp2, t0, 16); + tcg_gen_or_i32(t1, t1, tmp2); + tcg_gen_mov_i32(t0, tmp); + + dead_tmp(tmp2); + dead_tmp(tmp); +} + +static void gen_neon_unzip(int reg, int q, int tmp, int size) +{ + int n; + TCGv t0, t1; + + for (n = 0; n < q + 1; n += 2) { + t0 = neon_load_reg(reg, n); + t1 = neon_load_reg(reg, n + 1); + switch (size) { + case 0: gen_neon_unzip_u8(t0, t1); break; + case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same. */ + case 2: /* no-op */; break; + default: abort(); + } + neon_store_scratch(tmp + n, t0); + neon_store_scratch(tmp + n + 1, t1); + } +} + +static void gen_neon_trn_u8(TCGv t0, TCGv t1) +{ + TCGv rd, tmp; + + rd = new_tmp(); + tmp = new_tmp(); + + tcg_gen_shli_i32(rd, t0, 8); + tcg_gen_andi_i32(rd, rd, 0xff00ff00); + tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(t1, t1, 8); + tcg_gen_andi_i32(t1, t1, 0x00ff00ff); + tcg_gen_andi_i32(tmp, t0, 0xff00ff00); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rd); +} + +static void gen_neon_trn_u16(TCGv t0, TCGv t1) +{ + TCGv rd, tmp; + + rd = new_tmp(); + tmp = new_tmp(); + + tcg_gen_shli_i32(rd, t0, 16); + tcg_gen_andi_i32(tmp, t1, 0xffff); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shri_i32(t1, t1, 16); + tcg_gen_andi_i32(tmp, t0, 0xffff0000); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + dead_tmp(tmp); + dead_tmp(rd); +} + + +static struct { + int nregs; + int interleave; + int spacing; +} neon_ls_element_type[11] = { + {4, 4, 1}, + {4, 4, 2}, + {4, 1, 1}, + {4, 2, 1}, + {3, 3, 1}, + {3, 3, 2}, + {3, 1, 1}, + {1, 1, 1}, + {2, 2, 1}, + {2, 2, 2}, + {2, 1, 1} +}; + +/* Translate a NEON load/store element instruction. Return nonzero if the + instruction is invalid. */ +static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int rd, rn, rm; + int op; + int nregs; + int interleave; + int spacing; + int stride; + int size; + int reg; + int pass; + int load; + int shift; + int n; + TCGv addr; + TCGv tmp; + TCGv tmp2; + TCGv_i64 tmp64; + + if (!vfp_enabled(env)) + return 1; + VFP_DREG_D(rd, insn); + rn = (insn >> 16) & 0xf; + rm = insn & 0xf; + load = (insn & (1 << 21)) != 0; + addr = new_tmp(); + if ((insn & (1 << 23)) == 0) { + /* Load store all elements. */ + op = (insn >> 8) & 0xf; + size = (insn >> 6) & 3; + if (op > 10) + return 1; + nregs = neon_ls_element_type[op].nregs; + interleave = neon_ls_element_type[op].interleave; + spacing = neon_ls_element_type[op].spacing; + if (size == 3 && (interleave | spacing) != 1) + return 1; + load_reg_var(s, addr, rn); + stride = (1 << size) * interleave; + for (reg = 0; reg < nregs; reg++) { + if (interleave > 2 || (interleave == 2 && nregs == 2)) { + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, (1 << size) * reg); + } else if (interleave == 2 && nregs == 4 && reg == 2) { + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, 1 << size); + } + if (size == 3) { + if (load) { + tmp64 = gen_ld64(addr, IS_USER(s)); + neon_store_reg64(tmp64, rd); + tcg_temp_free_i64(tmp64); + } else { + tmp64 = tcg_temp_new_i64(); + neon_load_reg64(tmp64, rd); + gen_st64(tmp64, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, stride); + } else { + for (pass = 0; pass < 2; pass++) { + if (size == 2) { + if (load) { + tmp = gen_ld32(addr, IS_USER(s)); + neon_store_reg(rd, pass, tmp); + } else { + tmp = neon_load_reg(rd, pass); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, stride); + } else if (size == 1) { + if (load) { + tmp = gen_ld16u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + tmp2 = gen_ld16u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + gen_bfi(tmp, tmp, tmp2, 16, 0xffff); + dead_tmp(tmp2); + neon_store_reg(rd, pass, tmp); + } else { + tmp = neon_load_reg(rd, pass); + tmp2 = new_tmp(); + tcg_gen_shri_i32(tmp2, tmp, 16); + gen_st16(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + gen_st16(tmp2, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + } + } else /* size == 0 */ { + if (load) { + TCGV_UNUSED(tmp2); + for (n = 0; n < 4; n++) { + tmp = gen_ld8u(addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + if (n == 0) { + tmp2 = tmp; + } else { + gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff); + dead_tmp(tmp); + } + } + neon_store_reg(rd, pass, tmp2); + } else { + tmp2 = neon_load_reg(rd, pass); + for (n = 0; n < 4; n++) { + tmp = new_tmp(); + if (n == 0) { + tcg_gen_mov_i32(tmp, tmp2); + } else { + tcg_gen_shri_i32(tmp, tmp2, n * 8); + } + gen_st8(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, stride); + } + dead_tmp(tmp2); + } + } + } + } + rd += spacing; + } + stride = nregs * 8; + } else { + size = (insn >> 10) & 3; + if (size == 3) { + /* Load single element to all lanes. */ + if (!load) + return 1; + size = (insn >> 6) & 3; + nregs = ((insn >> 8) & 3) + 1; + stride = (insn & (1 << 5)) ? 2 : 1; + load_reg_var(s, addr, rn); + for (reg = 0; reg < nregs; reg++) { + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + gen_neon_dup_u8(tmp, 0); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + gen_neon_dup_low16(tmp); + break; + case 2: + tmp = gen_ld32(addr, IS_USER(s)); + break; + case 3: + return 1; + default: /* Avoid compiler warnings. */ + abort(); + } + tcg_gen_addi_i32(addr, addr, 1 << size); + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); + rd += stride; + } + stride = (1 << size) * nregs; + } else { + /* Single element. */ + pass = (insn >> 7) & 1; + switch (size) { + case 0: + shift = ((insn >> 5) & 3) * 8; + stride = 1; + break; + case 1: + shift = ((insn >> 6) & 1) * 16; + stride = (insn & (1 << 5)) ? 2 : 1; + break; + case 2: + shift = 0; + stride = (insn & (1 << 6)) ? 2 : 1; + break; + default: + abort(); + } + nregs = ((insn >> 8) & 3) + 1; + load_reg_var(s, addr, rn); + for (reg = 0; reg < nregs; reg++) { + if (load) { + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: /* Avoid compiler warnings. */ + abort(); + } + if (size != 2) { + tmp2 = neon_load_reg(rd, pass); + gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff); + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } else { /* Store */ + tmp = neon_load_reg(rd, pass); + if (shift) + tcg_gen_shri_i32(tmp, tmp, shift); + switch (size) { + case 0: + gen_st8(tmp, addr, IS_USER(s)); + break; + case 1: + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: + gen_st32(tmp, addr, IS_USER(s)); + break; + } + } + rd += stride; + tcg_gen_addi_i32(addr, addr, 1 << size); + } + stride = nregs * (1 << size); + } + } + dead_tmp(addr); + if (rm != 15) { + TCGv base; + + base = load_reg(s, rn); + if (rm == 13) { + tcg_gen_addi_i32(base, base, stride); + } else { + TCGv index; + index = load_reg(s, rm); + tcg_gen_add_i32(base, base, index); + dead_tmp(index); + } + store_reg(s, rn, base); + } + return 0; +} + +/* Bitwise select. dest = c ? t : f. Clobbers T and F. */ +static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c) +{ + tcg_gen_and_i32(t, t, c); + tcg_gen_andc_i32(f, f, c); + tcg_gen_or_i32(dest, t, f); +} + +static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_u8(dest, src); break; + case 1: gen_helper_neon_narrow_u16(dest, src); break; + case 2: tcg_gen_trunc_i64_i32(dest, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src) +{ + switch (size) { + case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; + case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; + case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; + default: abort(); + } +} + +static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift, + int q, int u) +{ + if (q) { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_rshl_s16(var, var, shift); break; + case 2: gen_helper_neon_rshl_s32(var, var, shift); break; + default: abort(); + } + } + } else { + if (u) { + switch (size) { + case 1: gen_helper_neon_rshl_u16(var, var, shift); break; + case 2: gen_helper_neon_rshl_u32(var, var, shift); break; + default: abort(); + } + } else { + switch (size) { + case 1: gen_helper_neon_shl_s16(var, var, shift); break; + case 2: gen_helper_neon_shl_s32(var, var, shift); break; + default: abort(); + } + } + } +} + +static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u) +{ + if (u) { + switch (size) { + case 0: gen_helper_neon_widen_u8(dest, src); break; + case 1: gen_helper_neon_widen_u16(dest, src); break; + case 2: tcg_gen_extu_i32_i64(dest, src); break; + default: abort(); + } + } else { + switch (size) { + case 0: gen_helper_neon_widen_s8(dest, src); break; + case 1: gen_helper_neon_widen_s16(dest, src); break; + case 2: tcg_gen_ext_i32_i64(dest, src); break; + default: abort(); + } + } + dead_tmp(src); +} + +static inline void gen_neon_addl(int size) +{ + switch (size) { + case 0: gen_helper_neon_addl_u16(CPU_V001); break; + case 1: gen_helper_neon_addl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_subl(int size) +{ + switch (size) { + case 0: gen_helper_neon_subl_u16(CPU_V001); break; + case 1: gen_helper_neon_subl_u32(CPU_V001); break; + case 2: tcg_gen_sub_i64(CPU_V001); break; + default: abort(); + } +} + +static inline void gen_neon_negl(TCGv_i64 var, int size) +{ + switch (size) { + case 0: gen_helper_neon_negl_u16(var, var); break; + case 1: gen_helper_neon_negl_u32(var, var); break; + case 2: gen_helper_neon_negl_u64(var, var); break; + default: abort(); + } +} + +static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size) +{ + switch (size) { + case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break; + case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break; + default: abort(); + } +} + +static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u) +{ + TCGv_i64 tmp; + + switch ((size << 1) | u) { + case 0: gen_helper_neon_mull_s8(dest, a, b); break; + case 1: gen_helper_neon_mull_u8(dest, a, b); break; + case 2: gen_helper_neon_mull_s16(dest, a, b); break; + case 3: gen_helper_neon_mull_u16(dest, a, b); break; + case 4: + tmp = gen_muls_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + case 5: + tmp = gen_mulu_i64_i32(a, b); + tcg_gen_mov_i64(dest, tmp); + break; + default: abort(); + } +} + +/* Translate a NEON data processing instruction. Return nonzero if the + instruction is invalid. + We process data in a mixture of 32-bit and 64-bit chunks. + Mostly we use 32-bit chunks so we can use normal scalar instructions. */ + +static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int op; + int q; + int rd, rn, rm; + int size; + int shift; + int pass; + int count; + int pairwise; + int u; + int n; + uint32_t imm, mask; + TCGv tmp, tmp2, tmp3, tmp4, tmp5; + TCGv_i64 tmp64; + + if (!vfp_enabled(env)) + return 1; + q = (insn & (1 << 6)) != 0; + u = (insn >> 24) & 1; + VFP_DREG_D(rd, insn); + VFP_DREG_N(rn, insn); + VFP_DREG_M(rm, insn); + size = (insn >> 20) & 3; + if ((insn & (1 << 23)) == 0) { + /* Three register same length. */ + op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); + if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9 + || op == 10 || op == 11 || op == 16)) { + /* 64-bit element instructions. */ + for (pass = 0; pass < (q ? 2 : 1); pass++) { + neon_load_reg64(cpu_V0, rn + pass); + neon_load_reg64(cpu_V1, rm + pass); + switch (op) { + case 1: /* VQADD */ + if (u) { + gen_helper_neon_add_saturate_u64(CPU_V001); + } else { + gen_helper_neon_add_saturate_s64(CPU_V001); + } + break; + case 5: /* VQSUB */ + if (u) { + gen_helper_neon_sub_saturate_u64(CPU_V001); + } else { + gen_helper_neon_sub_saturate_s64(CPU_V001); + } + break; + case 8: /* VSHL */ + if (u) { + gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 9: /* VQSHL */ + if (u) { + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, + cpu_V0, cpu_V0); + } else { + gen_helper_neon_qshl_s64(cpu_V1, cpu_env, + cpu_V1, cpu_V0); + } + break; + case 10: /* VRSHL */ + if (u) { + gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); + } else { + gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); + } + break; + case 11: /* VQRSHL */ + if (u) { + gen_helper_neon_qrshl_u64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); + } else { + gen_helper_neon_qrshl_s64(cpu_V0, cpu_env, + cpu_V1, cpu_V0); + } + break; + case 16: + if (u) { + tcg_gen_sub_i64(CPU_V001); + } else { + tcg_gen_add_i64(CPU_V001); + } + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } + return 0; + } + switch (op) { + case 8: /* VSHL */ + case 9: /* VQSHL */ + case 10: /* VRSHL */ + case 11: /* VQRSHL */ + { + int rtmp; + /* Shift instruction operands are reversed. */ + rtmp = rn; + rn = rm; + rm = rtmp; + pairwise = 0; + } + break; + case 20: /* VPMAX */ + case 21: /* VPMIN */ + case 23: /* VPADD */ + pairwise = 1; + break; + case 26: /* VPADD (float) */ + pairwise = (u && size < 2); + break; + case 30: /* VPMIN/VPMAX (float) */ + pairwise = u; + break; + default: + pairwise = 0; + break; + } + + for (pass = 0; pass < (q ? 4 : 2); pass++) { + + if (pairwise) { + /* Pairwise. */ + if (q) + n = (pass & 1) * 2; + else + n = 0; + if (pass < q + 1) { + tmp = neon_load_reg(rn, n); + tmp2 = neon_load_reg(rn, n + 1); + } else { + tmp = neon_load_reg(rm, n); + tmp2 = neon_load_reg(rm, n + 1); + } + } else { + /* Elementwise. */ + tmp = neon_load_reg(rn, pass); + tmp2 = neon_load_reg(rm, pass); + } + switch (op) { + case 0: /* VHADD */ + GEN_NEON_INTEGER_OP(hadd); + break; + case 1: /* VQADD */ + GEN_NEON_INTEGER_OP_ENV(qadd); + break; + case 2: /* VRHADD */ + GEN_NEON_INTEGER_OP(rhadd); + break; + case 3: /* Logic ops. */ + switch ((u << 2) | size) { + case 0: /* VAND */ + tcg_gen_and_i32(tmp, tmp, tmp2); + break; + case 1: /* BIC */ + tcg_gen_andc_i32(tmp, tmp, tmp2); + break; + case 2: /* VORR */ + tcg_gen_or_i32(tmp, tmp, tmp2); + break; + case 3: /* VORN */ + tcg_gen_orc_i32(tmp, tmp, tmp2); + break; + case 4: /* VEOR */ + tcg_gen_xor_i32(tmp, tmp, tmp2); + break; + case 5: /* VBSL */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp, tmp2, tmp3); + dead_tmp(tmp3); + break; + case 6: /* VBIT */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp, tmp3, tmp2); + dead_tmp(tmp3); + break; + case 7: /* VBIF */ + tmp3 = neon_load_reg(rd, pass); + gen_neon_bsl(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + break; + } + break; + case 4: /* VHSUB */ + GEN_NEON_INTEGER_OP(hsub); + break; + case 5: /* VQSUB */ + GEN_NEON_INTEGER_OP_ENV(qsub); + break; + case 6: /* VCGT */ + GEN_NEON_INTEGER_OP(cgt); + break; + case 7: /* VCGE */ + GEN_NEON_INTEGER_OP(cge); + break; + case 8: /* VSHL */ + GEN_NEON_INTEGER_OP(shl); + break; + case 9: /* VQSHL */ + GEN_NEON_INTEGER_OP_ENV(qshl); + break; + case 10: /* VRSHL */ + GEN_NEON_INTEGER_OP(rshl); + break; + case 11: /* VQRSHL */ + GEN_NEON_INTEGER_OP_ENV(qrshl); + break; + case 12: /* VMAX */ + GEN_NEON_INTEGER_OP(max); + break; + case 13: /* VMIN */ + GEN_NEON_INTEGER_OP(min); + break; + case 14: /* VABD */ + GEN_NEON_INTEGER_OP(abd); + break; + case 15: /* VABA */ + GEN_NEON_INTEGER_OP(abd); + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + gen_neon_add(size, tmp, tmp2); + break; + case 16: + if (!u) { /* VADD */ + if (gen_neon_add(size, tmp, tmp2)) + return 1; + } else { /* VSUB */ + switch (size) { + case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 17: + if (!u) { /* VTST */ + switch (size) { + case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break; + default: return 1; + } + } else { /* VCEQ */ + switch (size) { + case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 18: /* Multiply. */ + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + if (u) { /* VMLS */ + gen_neon_rsb(size, tmp, tmp2); + } else { /* VMLA */ + gen_neon_add(size, tmp, tmp2); + } + break; + case 19: /* VMUL */ + if (u) { /* polynomial */ + gen_helper_neon_mul_p8(tmp, tmp, tmp2); + } else { /* Integer */ + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + break; + case 20: /* VPMAX */ + GEN_NEON_INTEGER_OP(pmax); + break; + case 21: /* VPMIN */ + GEN_NEON_INTEGER_OP(pmin); + break; + case 22: /* Hultiply high. */ + if (!u) { /* VQDMULH */ + switch (size) { + case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + } else { /* VQRDHMUL */ + switch (size) { + case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + } + break; + case 23: /* VPADD */ + if (u) + return 1; + switch (size) { + case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break; + default: return 1; + } + break; + case 26: /* Floating point arithnetic. */ + switch ((u << 2) | size) { + case 0: /* VADD */ + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 2: /* VSUB */ + gen_helper_neon_sub_f32(tmp, tmp, tmp2); + break; + case 4: /* VPADD */ + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 6: /* VABD */ + gen_helper_neon_abd_f32(tmp, tmp, tmp2); + break; + default: + return 1; + } + break; + case 27: /* Float multiply. */ + gen_helper_neon_mul_f32(tmp, tmp, tmp2); + if (!u) { + dead_tmp(tmp2); + tmp2 = neon_load_reg(rd, pass); + if (size == 0) { + gen_helper_neon_add_f32(tmp, tmp, tmp2); + } else { + gen_helper_neon_sub_f32(tmp, tmp2, tmp); + } + } + break; + case 28: /* Float compare. */ + if (!u) { + gen_helper_neon_ceq_f32(tmp, tmp, tmp2); + } else { + if (size == 0) + gen_helper_neon_cge_f32(tmp, tmp, tmp2); + else + gen_helper_neon_cgt_f32(tmp, tmp, tmp2); + } + break; + case 29: /* Float compare absolute. */ + if (!u) + return 1; + if (size == 0) + gen_helper_neon_acge_f32(tmp, tmp, tmp2); + else + gen_helper_neon_acgt_f32(tmp, tmp, tmp2); + break; + case 30: /* Float min/max. */ + if (size == 0) + gen_helper_neon_max_f32(tmp, tmp, tmp2); + else + gen_helper_neon_min_f32(tmp, tmp, tmp2); + break; + case 31: + if (size == 0) + gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env); + else + gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env); + break; + default: + abort(); + } + dead_tmp(tmp2); + + /* Save the result. For elementwise operations we can put it + straight into the destination register. For pairwise operations + we have to be careful to avoid clobbering the source operands. */ + if (pairwise && rd == rm) { + neon_store_scratch(pass, tmp); + } else { + neon_store_reg(rd, pass, tmp); + } + + } /* for pass */ + if (pairwise && rd == rm) { + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tmp = neon_load_scratch(pass); + neon_store_reg(rd, pass, tmp); + } + } + /* End of 3 register same size operations. */ + } else if (insn & (1 << 4)) { + if ((insn & 0x00380080) != 0) { + /* Two registers and shift. */ + op = (insn >> 8) & 0xf; + if (insn & (1 << 7)) { + /* 64-bit shift. */ + size = 3; + } else { + size = 2; + while ((insn & (1 << (size + 19))) == 0) + size--; + } + shift = (insn >> 16) & ((1 << (3 + size)) - 1); + /* To avoid excessive dumplication of ops we implement shift + by immediate using the variable shift operations. */ + if (op < 8) { + /* Shift by immediate: + VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ + /* Right shifts are encoded as N - shift, where N is the + element size in bits. */ + if (op <= 4) + shift = shift - (1 << (size + 3)); + if (size == 3) { + count = q + 1; + } else { + count = q ? 4: 2; + } + switch (size) { + case 0: + imm = (uint8_t) shift; + imm |= imm << 8; + imm |= imm << 16; + break; + case 1: + imm = (uint16_t) shift; + imm |= imm << 16; + break; + case 2: + case 3: + imm = shift; + break; + default: + abort(); + } + + for (pass = 0; pass < count; pass++) { + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + tcg_gen_movi_i64(cpu_V1, imm); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + else + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1); + break; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1); + else + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); + break; + case 4: /* VSRI */ + if (!u) + return 1; + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 5: /* VSHL, VSLI */ + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); + break; + case 6: /* VQSHL */ + if (u) + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + else + gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + break; + case 7: /* VQSHLU */ + gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1); + break; + } + if (op == 1 || op == 3) { + /* Accumulate. */ + neon_load_reg64(cpu_V0, rd + pass); + tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + cpu_abort(env, "VS[LR]I.64 not implemented"); + } + neon_store_reg64(cpu_V0, rd + pass); + } else { /* size < 3 */ + /* Operands in T0 and T1. */ + tmp = neon_load_reg(rm, pass); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, imm); + switch (op) { + case 0: /* VSHR */ + case 1: /* VSRA */ + GEN_NEON_INTEGER_OP(shl); + break; + case 2: /* VRSHR */ + case 3: /* VRSRA */ + GEN_NEON_INTEGER_OP(rshl); + break; + case 4: /* VSRI */ + if (!u) + return 1; + GEN_NEON_INTEGER_OP(shl); + break; + case 5: /* VSHL, VSLI */ + switch (size) { + case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break; + default: return 1; + } + break; + case 6: /* VQSHL */ + GEN_NEON_INTEGER_OP_ENV(qshl); + break; + case 7: /* VQSHLU */ + switch (size) { + case 0: gen_helper_neon_qshl_u8(tmp, cpu_env, tmp, tmp2); break; + case 1: gen_helper_neon_qshl_u16(tmp, cpu_env, tmp, tmp2); break; + case 2: gen_helper_neon_qshl_u32(tmp, cpu_env, tmp, tmp2); break; + default: return 1; + } + break; + } + dead_tmp(tmp2); + + if (op == 1 || op == 3) { + /* Accumulate. */ + tmp2 = neon_load_reg(rd, pass); + gen_neon_add(size, tmp2, tmp); + dead_tmp(tmp2); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + switch (size) { + case 0: + if (op == 4) + mask = 0xff >> -shift; + else + mask = (uint8_t)(0xff << shift); + mask |= mask << 8; + mask |= mask << 16; + break; + case 1: + if (op == 4) + mask = 0xffff >> -shift; + else + mask = (uint16_t)(0xffff << shift); + mask |= mask << 16; + break; + case 2: + if (shift < -31 || shift > 31) { + mask = 0; + } else { + if (op == 4) + mask = 0xffffffffu >> -shift; + else + mask = 0xffffffffu << shift; + } + break; + default: + abort(); + } + tmp2 = neon_load_reg(rd, pass); + tcg_gen_andi_i32(tmp, tmp, mask); + tcg_gen_andi_i32(tmp2, tmp2, ~mask); + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } + } /* for pass */ + } else if (op < 10) { + /* Shift by immediate and narrow: + VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ + shift = shift - (1 << (size + 3)); + size++; + switch (size) { + case 1: + imm = (uint16_t)shift; + imm |= imm << 16; + tmp2 = tcg_const_i32(imm); + TCGV_UNUSED_I64(tmp64); + break; + case 2: + imm = (uint32_t)shift; + tmp2 = tcg_const_i32(imm); + TCGV_UNUSED_I64(tmp64); + break; + case 3: + tmp64 = tcg_const_i64(shift); + TCGV_UNUSED(tmp2); + break; + default: + abort(); + } + + for (pass = 0; pass < 2; pass++) { + if (size == 3) { + neon_load_reg64(cpu_V0, rm + pass); + if (q) { + if (u) + gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64); + else + gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64); + } else { + if (u) + gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64); + else + gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64); + } + } else { + tmp = neon_load_reg(rm + pass, 0); + gen_neon_shift_narrow(size, tmp, tmp2, q, u); + tmp3 = neon_load_reg(rm + pass, 1); + gen_neon_shift_narrow(size, tmp3, tmp2, q, u); + tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3); + dead_tmp(tmp); + dead_tmp(tmp3); + } + tmp = new_tmp(); + if (op == 8 && !u) { + gen_neon_narrow(size - 1, tmp, cpu_V0); + } else { + if (op == 8) + gen_neon_narrow_sats(size - 1, tmp, cpu_V0); + else + gen_neon_narrow_satu(size - 1, tmp, cpu_V0); + } + neon_store_reg(rd, pass, tmp); + } /* for pass */ + if (size == 3) { + tcg_temp_free_i64(tmp64); + } else { + dead_tmp(tmp2); + } + } else if (op == 10) { + /* VSHLL */ + if (q || size == 3) + return 1; + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + for (pass = 0; pass < 2; pass++) { + if (pass == 1) + tmp = tmp2; + + gen_neon_widen(cpu_V0, tmp, size, u); + + if (shift != 0) { + /* The shift is less than the width of the source + type, so we can just shift the whole register. */ + tcg_gen_shli_i64(cpu_V0, cpu_V0, shift); + if (size < 2 || !u) { + uint64_t imm64; + if (size == 0) { + imm = (0xffu >> (8 - shift)); + imm |= imm << 16; + } else { + imm = 0xffff >> (16 - shift); + } + imm64 = imm | (((uint64_t)imm) << 32); + tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64); + } + } + neon_store_reg64(cpu_V0, rd + pass); + } + } else if (op == 15 || op == 16) { + /* VCVT fixed-point. */ + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); + if (op & 1) { + if (u) + gen_vfp_ulto(0, shift); + else + gen_vfp_slto(0, shift); + } else { + if (u) + gen_vfp_toul(0, shift); + else + gen_vfp_tosl(0, shift); + } + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); + } + } else { + return 1; + } + } else { /* (insn & 0x00380080) == 0 */ + int invert; + + op = (insn >> 8) & 0xf; + /* One register and immediate. */ + imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); + invert = (insn & (1 << 5)) != 0; + switch (op) { + case 0: case 1: + /* no-op */ + break; + case 2: case 3: + imm <<= 8; + break; + case 4: case 5: + imm <<= 16; + break; + case 6: case 7: + imm <<= 24; + break; + case 8: case 9: + imm |= imm << 16; + break; + case 10: case 11: + imm = (imm << 8) | (imm << 24); + break; + case 12: + imm = (imm < 8) | 0xff; + break; + case 13: + imm = (imm << 16) | 0xffff; + break; + case 14: + imm |= (imm << 8) | (imm << 16) | (imm << 24); + if (invert) + imm = ~imm; + break; + case 15: + imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) + | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); + break; + } + if (invert) + imm = ~imm; + + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op & 1 && op < 12) { + tmp = neon_load_reg(rd, pass); + if (invert) { + /* The immediate value has already been inverted, so + BIC becomes AND. */ + tcg_gen_andi_i32(tmp, tmp, imm); + } else { + tcg_gen_ori_i32(tmp, tmp, imm); + } + } else { + /* VMOV, VMVN. */ + tmp = new_tmp(); + if (op == 14 && invert) { + uint32_t val; + val = 0; + for (n = 0; n < 4; n++) { + if (imm & (1 << (n + (pass & 1) * 4))) + val |= 0xff << (n * 8); + } + tcg_gen_movi_i32(tmp, val); + } else { + tcg_gen_movi_i32(tmp, imm); + } + } + neon_store_reg(rd, pass, tmp); + } + } + } else { /* (insn & 0x00800010 == 0x00800000) */ + if (size != 3) { + op = (insn >> 8) & 0xf; + if ((insn & (1 << 6)) == 0) { + /* Three registers of different lengths. */ + int src1_wide; + int src2_wide; + int prewiden; + /* prewiden, src1_wide, src2_wide */ + static const int neon_3reg_wide[16][3] = { + {1, 0, 0}, /* VADDL */ + {1, 1, 0}, /* VADDW */ + {1, 0, 0}, /* VSUBL */ + {1, 1, 0}, /* VSUBW */ + {0, 1, 1}, /* VADDHN */ + {0, 0, 0}, /* VABAL */ + {0, 1, 1}, /* VSUBHN */ + {0, 0, 0}, /* VABDL */ + {0, 0, 0}, /* VMLAL */ + {0, 0, 0}, /* VQDMLAL */ + {0, 0, 0}, /* VMLSL */ + {0, 0, 0}, /* VQDMLSL */ + {0, 0, 0}, /* Integer VMULL */ + {0, 0, 0}, /* VQDMULL */ + {0, 0, 0} /* Polynomial VMULL */ + }; + + prewiden = neon_3reg_wide[op][0]; + src1_wide = neon_3reg_wide[op][1]; + src2_wide = neon_3reg_wide[op][2]; + + if (size == 0 && (op == 9 || op == 11 || op == 13)) + return 1; + + /* Avoid overlapping operands. Wide source operands are + always aligned so will never overlap with wide + destinations in problematic ways. */ + if (rd == rm && !src2_wide) { + tmp = neon_load_reg(rm, 1); + neon_store_scratch(2, tmp); + } else if (rd == rn && !src1_wide) { + tmp = neon_load_reg(rn, 1); + neon_store_scratch(2, tmp); + } + TCGV_UNUSED(tmp3); + for (pass = 0; pass < 2; pass++) { + if (src1_wide) { + neon_load_reg64(cpu_V0, rn + pass); + TCGV_UNUSED(tmp); + } else { + if (pass == 1 && rd == rn) { + tmp = neon_load_scratch(2); + } else { + tmp = neon_load_reg(rn, pass); + } + if (prewiden) { + gen_neon_widen(cpu_V0, tmp, size, u); + } + } + if (src2_wide) { + neon_load_reg64(cpu_V1, rm + pass); + TCGV_UNUSED(tmp2); + } else { + if (pass == 1 && rd == rm) { + tmp2 = neon_load_scratch(2); + } else { + tmp2 = neon_load_reg(rm, pass); + } + if (prewiden) { + gen_neon_widen(cpu_V1, tmp2, size, u); + } + } + switch (op) { + case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ + gen_neon_addl(size); + break; + case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */ + gen_neon_subl(size); + break; + case 5: case 7: /* VABAL, VABDL */ + switch ((size << 1) | u) { + case 0: + gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2); + break; + case 1: + gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2); + break; + case 2: + gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2); + break; + case 3: + gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2); + break; + case 4: + gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2); + break; + case 5: + gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2); + break; + default: abort(); + } + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 8: case 9: case 10: case 11: case 12: case 13: + /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 14: /* Polynomial VMULL */ + cpu_abort(env, "Polynomial VMULL not implemented"); + + default: /* 15 is RESERVED. */ + return 1; + } + if (op == 5 || op == 13 || (op >= 8 && op <= 11)) { + /* Accumulate. */ + if (op == 10 || op == 11) { + gen_neon_negl(cpu_V0, size); + } + + if (op != 13) { + neon_load_reg64(cpu_V1, rd + pass); + } + + switch (op) { + case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */ + gen_neon_addl(size); + break; + case 9: case 11: /* VQDMLAL, VQDMLSL */ + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); + break; + /* Fall through. */ + case 13: /* VQDMULL */ + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } else if (op == 4 || op == 6) { + /* Narrowing operation. */ + tmp = new_tmp(); + if (u) { + switch (size) { + case 0: + gen_helper_neon_narrow_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; + default: abort(); + } + } else { + switch (size) { + case 0: + gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0); + break; + case 1: + gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0); + break; + case 2: + tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31); + tcg_gen_shri_i64(cpu_V0, cpu_V0, 32); + tcg_gen_trunc_i64_i32(tmp, cpu_V0); + break; + default: abort(); + } + } + if (pass == 0) { + tmp3 = tmp; + } else { + neon_store_reg(rd, 0, tmp3); + neon_store_reg(rd, 1, tmp); + } + } else { + /* Write back the result. */ + neon_store_reg64(cpu_V0, rd + pass); + } + } + } else { + /* Two registers and a scalar. */ + switch (op) { + case 0: /* Integer VMLA scalar */ + case 1: /* Float VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 5: /* Floating point VMLS scalar */ + case 8: /* Integer VMUL scalar */ + case 9: /* Floating point VMUL scalar */ + case 12: /* VQDMULH scalar */ + case 13: /* VQRDMULH scalar */ + tmp = neon_get_scalar(size, rm); + neon_store_scratch(0, tmp); + for (pass = 0; pass < (u ? 4 : 2); pass++) { + tmp = neon_load_scratch(0); + tmp2 = neon_load_reg(rn, pass); + if (op == 12) { + if (size == 1) { + gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); + } else { + gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); + } + } else if (op == 13) { + if (size == 1) { + gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); + } else { + gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); + } + } else if (op & 1) { + gen_helper_neon_mul_f32(tmp, tmp, tmp2); + } else { + switch (size) { + case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; + case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; + default: return 1; + } + } + dead_tmp(tmp2); + if (op < 8) { + /* Accumulate. */ + tmp2 = neon_load_reg(rd, pass); + switch (op) { + case 0: + gen_neon_add(size, tmp, tmp2); + break; + case 1: + gen_helper_neon_add_f32(tmp, tmp, tmp2); + break; + case 4: + gen_neon_rsb(size, tmp, tmp2); + break; + case 5: + gen_helper_neon_sub_f32(tmp, tmp2, tmp); + break; + default: + abort(); + } + dead_tmp(tmp2); + } + neon_store_reg(rd, pass, tmp); + } + break; + case 2: /* VMLAL sclar */ + case 3: /* VQDMLAL scalar */ + case 6: /* VMLSL scalar */ + case 7: /* VQDMLSL scalar */ + case 10: /* VMULL scalar */ + case 11: /* VQDMULL scalar */ + if (size == 0 && (op == 3 || op == 7 || op == 11)) + return 1; + + tmp2 = neon_get_scalar(size, rm); + tmp3 = neon_load_reg(rn, 1); + + for (pass = 0; pass < 2; pass++) { + if (pass == 0) { + tmp = neon_load_reg(rn, 0); + } else { + tmp = tmp3; + } + gen_neon_mull(cpu_V0, tmp, tmp2, size, u); + dead_tmp(tmp); + if (op == 6 || op == 7) { + gen_neon_negl(cpu_V0, size); + } + if (op != 11) { + neon_load_reg64(cpu_V1, rd + pass); + } + switch (op) { + case 2: case 6: + gen_neon_addl(size); + break; + case 3: case 7: + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + gen_neon_addl_saturate(cpu_V0, cpu_V1, size); + break; + case 10: + /* no-op */ + break; + case 11: + gen_neon_addl_saturate(cpu_V0, cpu_V0, size); + break; + default: + abort(); + } + neon_store_reg64(cpu_V0, rd + pass); + } + + dead_tmp(tmp2); + + break; + default: /* 14 and 15 are RESERVED */ + return 1; + } + } + } else { /* size == 3 */ + if (!u) { + /* Extract. */ + imm = (insn >> 8) & 0xf; + count = q + 1; + + if (imm > 7 && !q) + return 1; + + if (imm == 0) { + neon_load_reg64(cpu_V0, rn); + if (q) { + neon_load_reg64(cpu_V1, rn + 1); + } + } else if (imm == 8) { + neon_load_reg64(cpu_V0, rn + 1); + if (q) { + neon_load_reg64(cpu_V1, rm); + } + } else if (q) { + tmp64 = tcg_temp_new_i64(); + if (imm < 8) { + neon_load_reg64(cpu_V0, rn); + neon_load_reg64(tmp64, rn + 1); + } else { + neon_load_reg64(cpu_V0, rn + 1); + neon_load_reg64(tmp64, rm); + } + tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8); + tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + if (imm < 8) { + neon_load_reg64(cpu_V1, rm); + } else { + neon_load_reg64(cpu_V1, rm + 1); + imm -= 8; + } + tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_shri_i64(tmp64, tmp64, imm * 8); + tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* BUGFIX */ + neon_load_reg64(cpu_V0, rn); + tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8); + neon_load_reg64(cpu_V1, rm); + tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); + tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); + } + neon_store_reg64(cpu_V0, rd); + if (q) { + neon_store_reg64(cpu_V1, rd + 1); + } + } else if ((insn & (1 << 11)) == 0) { + /* Two register misc. */ + op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); + size = (insn >> 18) & 3; + switch (op) { + case 0: /* VREV64 */ + if (size == 3) + return 1; + for (pass = 0; pass < (q ? 2 : 1); pass++) { + tmp = neon_load_reg(rm, pass * 2); + tmp2 = neon_load_reg(rm, pass * 2 + 1); + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_swap_half(tmp); break; + case 2: /* no-op */ break; + default: abort(); + } + neon_store_reg(rd, pass * 2 + 1, tmp); + if (size == 2) { + neon_store_reg(rd, pass * 2, tmp2); + } else { + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break; + case 1: gen_swap_half(tmp2); break; + default: abort(); + } + neon_store_reg(rd, pass * 2, tmp2); + } + } + break; + case 4: case 5: /* VPADDL */ + case 12: case 13: /* VPADAL */ + if (size == 3) + return 1; + for (pass = 0; pass < q + 1; pass++) { + tmp = neon_load_reg(rm, pass * 2); + gen_neon_widen(cpu_V0, tmp, size, op & 1); + tmp = neon_load_reg(rm, pass * 2 + 1); + gen_neon_widen(cpu_V1, tmp, size, op & 1); + switch (size) { + case 0: gen_helper_neon_paddl_u16(CPU_V001); break; + case 1: gen_helper_neon_paddl_u32(CPU_V001); break; + case 2: tcg_gen_add_i64(CPU_V001); break; + default: abort(); + } + if (op >= 12) { + /* Accumulate. */ + neon_load_reg64(cpu_V1, rd + pass); + gen_neon_addl(size); + } + neon_store_reg64(cpu_V0, rd + pass); + } + break; + case 33: /* VTRN */ + if (size == 2) { + for (n = 0; n < (q ? 4 : 2); n += 2) { + tmp = neon_load_reg(rm, n); + tmp2 = neon_load_reg(rd, n + 1); + neon_store_reg(rm, n, tmp2); + neon_store_reg(rd, n + 1, tmp); + } + } else { + goto elementwise; + } + break; + case 34: /* VUZP */ + /* Reg Before After + Rd A3 A2 A1 A0 B2 B0 A2 A0 + Rm B3 B2 B1 B0 B3 B1 A3 A1 + */ + if (size == 3) + return 1; + gen_neon_unzip(rd, q, 0, size); + gen_neon_unzip(rm, q, 4, size); + if (q) { + static int unzip_order_q[8] = + {0, 2, 4, 6, 1, 3, 5, 7}; + for (n = 0; n < 8; n++) { + int reg = (n < 4) ? rd : rm; + tmp = neon_load_scratch(unzip_order_q[n]); + neon_store_reg(reg, n % 4, tmp); + } + } else { + static int unzip_order[4] = + {0, 4, 1, 5}; + for (n = 0; n < 4; n++) { + int reg = (n < 2) ? rd : rm; + tmp = neon_load_scratch(unzip_order[n]); + neon_store_reg(reg, n % 2, tmp); + } + } + break; + case 35: /* VZIP */ + /* Reg Before After + Rd A3 A2 A1 A0 B1 A1 B0 A0 + Rm B3 B2 B1 B0 B3 A3 B2 A2 + */ + if (size == 3) + return 1; + count = (q ? 4 : 2); + for (n = 0; n < count; n++) { + tmp = neon_load_reg(rd, n); + tmp2 = neon_load_reg(rd, n); + switch (size) { + case 0: gen_neon_zip_u8(tmp, tmp2); break; + case 1: gen_neon_zip_u16(tmp, tmp2); break; + case 2: /* no-op */; break; + default: abort(); + } + neon_store_scratch(n * 2, tmp); + neon_store_scratch(n * 2 + 1, tmp2); + } + for (n = 0; n < count * 2; n++) { + int reg = (n < count) ? rd : rm; + tmp = neon_load_scratch(n); + neon_store_reg(reg, n % count, tmp); + } + break; + case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ + if (size == 3) + return 1; + TCGV_UNUSED(tmp2); + for (pass = 0; pass < 2; pass++) { + neon_load_reg64(cpu_V0, rm + pass); + tmp = new_tmp(); + if (op == 36 && q == 0) { + gen_neon_narrow(size, tmp, cpu_V0); + } else if (q) { + gen_neon_narrow_satu(size, tmp, cpu_V0); + } else { + gen_neon_narrow_sats(size, tmp, cpu_V0); + } + if (pass == 0) { + tmp2 = tmp; + } else { + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp); + } + } + break; + case 38: /* VSHLL */ + if (q || size == 3) + return 1; + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + for (pass = 0; pass < 2; pass++) { + if (pass == 1) + tmp = tmp2; + gen_neon_widen(cpu_V0, tmp, size, 1); + neon_store_reg64(cpu_V0, rd + pass); + } + break; + case 44: /* VCVT.F16.F32 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp = new_tmp(); + tmp2 = new_tmp(); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0)); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1)); + gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp2, tmp2, tmp); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2)); + gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3)); + neon_store_reg(rd, 0, tmp2); + tmp2 = new_tmp(); + gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp2, tmp2, tmp); + neon_store_reg(rd, 1, tmp2); + dead_tmp(tmp); + break; + case 46: /* VCVT.F32.F16 */ + if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) + return 1; + tmp3 = new_tmp(); + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); + tcg_gen_ext16u_i32(tmp3, tmp); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0)); + tcg_gen_shri_i32(tmp3, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1)); + dead_tmp(tmp); + tcg_gen_ext16u_i32(tmp3, tmp2); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2)); + tcg_gen_shri_i32(tmp3, tmp2, 16); + gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3)); + dead_tmp(tmp2); + dead_tmp(tmp3); + break; + default: + elementwise: + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op == 30 || op == 31 || op >= 58) { + tcg_gen_ld_f32(cpu_F0s, cpu_env, + neon_reg_offset(rm, pass)); + TCGV_UNUSED(tmp); + } else { + tmp = neon_load_reg(rm, pass); + } + switch (op) { + case 1: /* VREV32 */ + switch (size) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_swap_half(tmp); break; + default: return 1; + } + break; + case 2: /* VREV16 */ + if (size != 0) + return 1; + gen_rev16(tmp); + break; + case 8: /* CLS */ + switch (size) { + case 0: gen_helper_neon_cls_s8(tmp, tmp); break; + case 1: gen_helper_neon_cls_s16(tmp, tmp); break; + case 2: gen_helper_neon_cls_s32(tmp, tmp); break; + default: return 1; + } + break; + case 9: /* CLZ */ + switch (size) { + case 0: gen_helper_neon_clz_u8(tmp, tmp); break; + case 1: gen_helper_neon_clz_u16(tmp, tmp); break; + case 2: gen_helper_clz(tmp, tmp); break; + default: return 1; + } + break; + case 10: /* CNT */ + if (size != 0) + return 1; + gen_helper_neon_cnt_u8(tmp, tmp); + break; + case 11: /* VNOT */ + if (size != 0) + return 1; + tcg_gen_not_i32(tmp, tmp); + break; + case 14: /* VQABS */ + switch (size) { + case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break; + case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break; + case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break; + default: return 1; + } + break; + case 15: /* VQNEG */ + switch (size) { + case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break; + case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break; + case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break; + default: return 1; + } + break; + case 16: case 19: /* VCGT #0, VCLE #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + if (op == 19) + tcg_gen_not_i32(tmp, tmp); + break; + case 17: case 20: /* VCGE #0, VCLT #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + if (op == 20) + tcg_gen_not_i32(tmp, tmp); + break; + case 18: /* VCEQ #0 */ + tmp2 = tcg_const_i32(0); + switch(size) { + case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; + case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; + default: return 1; + } + tcg_temp_free(tmp2); + break; + case 22: /* VABS */ + switch(size) { + case 0: gen_helper_neon_abs_s8(tmp, tmp); break; + case 1: gen_helper_neon_abs_s16(tmp, tmp); break; + case 2: tcg_gen_abs_i32(tmp, tmp); break; + default: return 1; + } + break; + case 23: /* VNEG */ + if (size == 3) + return 1; + tmp2 = tcg_const_i32(0); + gen_neon_rsb(size, tmp, tmp2); + tcg_temp_free(tmp2); + break; + case 24: case 27: /* Float VCGT #0, Float VCLE #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cgt_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + if (op == 27) + tcg_gen_not_i32(tmp, tmp); + break; + case 25: case 28: /* Float VCGE #0, Float VCLT #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cge_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + if (op == 28) + tcg_gen_not_i32(tmp, tmp); + break; + case 26: /* Float VCEQ #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_ceq_f32(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + break; + case 30: /* Float VABS */ + gen_vfp_abs(0); + break; + case 31: /* Float VNEG */ + gen_vfp_neg(0); + break; + case 32: /* VSWP */ + tmp2 = neon_load_reg(rd, pass); + neon_store_reg(rm, pass, tmp2); + break; + case 33: /* VTRN */ + tmp2 = neon_load_reg(rd, pass); + switch (size) { + case 0: gen_neon_trn_u8(tmp, tmp2); break; + case 1: gen_neon_trn_u16(tmp, tmp2); break; + case 2: abort(); + default: return 1; + } + neon_store_reg(rm, pass, tmp2); + break; + case 56: /* Integer VRECPE */ + gen_helper_recpe_u32(tmp, tmp, cpu_env); + break; + case 57: /* Integer VRSQRTE */ + gen_helper_rsqrte_u32(tmp, tmp, cpu_env); + break; + case 58: /* Float VRECPE */ + gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); + break; + case 59: /* Float VRSQRTE */ + gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); + break; + case 60: /* VCVT.F32.S32 */ + gen_vfp_tosiz(0); + break; + case 61: /* VCVT.F32.U32 */ + gen_vfp_touiz(0); + break; + case 62: /* VCVT.S32.F32 */ + gen_vfp_sito(0); + break; + case 63: /* VCVT.U32.F32 */ + gen_vfp_uito(0); + break; + default: + /* Reserved: 21, 29, 39-56 */ + return 1; + } + if (op == 30 || op == 31 || op >= 58) { + tcg_gen_st_f32(cpu_F0s, cpu_env, + neon_reg_offset(rd, pass)); + } else { + neon_store_reg(rd, pass, tmp); + } + } + break; + } + } else if ((insn & (1 << 10)) == 0) { + /* VTBL, VTBX. */ + n = ((insn >> 5) & 0x18) + 8; + if (insn & (1 << 6)) { + tmp = neon_load_reg(rd, 0); + } else { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } + tmp2 = neon_load_reg(rm, 0); + tmp4 = tcg_const_i32(rn); + tmp5 = tcg_const_i32(n); + gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5); + dead_tmp(tmp); + if (insn & (1 << 6)) { + tmp = neon_load_reg(rd, 1); + } else { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } + tmp3 = neon_load_reg(rm, 1); + gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5); + tcg_temp_free_i32(tmp5); + tcg_temp_free_i32(tmp4); + neon_store_reg(rd, 0, tmp2); + neon_store_reg(rd, 1, tmp3); + dead_tmp(tmp); + } else if ((insn & 0x380) == 0) { + /* VDUP */ + if (insn & (1 << 19)) { + tmp = neon_load_reg(rm, 1); + } else { + tmp = neon_load_reg(rm, 0); + } + if (insn & (1 << 16)) { + gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8); + } else if (insn & (1 << 17)) { + if ((insn >> 18) & 1) + gen_neon_dup_high16(tmp); + else + gen_neon_dup_low16(tmp); + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { + tmp2 = new_tmp(); + tcg_gen_mov_i32(tmp2, tmp); + neon_store_reg(rd, pass, tmp2); + } + dead_tmp(tmp); + } else { + return 1; + } + } + } + return 0; +} + +static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn) +{ + int crn = (insn >> 16) & 0xf; + int crm = insn & 0xf; + int op1 = (insn >> 21) & 7; + int op2 = (insn >> 5) & 7; + int rt = (insn >> 12) & 0xf; + TCGv tmp; + + if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { + if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { + /* TEECR */ + if (IS_USER(s)) + return 1; + tmp = load_cpu_field(teecr); + store_reg(s, rt, tmp); + return 0; + } + if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { + /* TEEHBR */ + if (IS_USER(s) && (env->teecr & 1)) + return 1; + tmp = load_cpu_field(teehbr); + store_reg(s, rt, tmp); + return 0; + } + } + fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n", + op1, crn, crm, op2); + return 1; +} + +static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn) +{ + int crn = (insn >> 16) & 0xf; + int crm = insn & 0xf; + int op1 = (insn >> 21) & 7; + int op2 = (insn >> 5) & 7; + int rt = (insn >> 12) & 0xf; + TCGv tmp; + + if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { + if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) { + /* TEECR */ + if (IS_USER(s)) + return 1; + tmp = load_reg(s, rt); + gen_helper_set_teecr(cpu_env, tmp); + dead_tmp(tmp); + return 0; + } + if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) { + /* TEEHBR */ + if (IS_USER(s) && (env->teecr & 1)) + return 1; + tmp = load_reg(s, rt); + store_cpu_field(tmp, teehbr); + return 0; + } + } + fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n", + op1, crn, crm, op2); + return 1; +} + +static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int cpnum; + + cpnum = (insn >> 8) & 0xf; + if (arm_feature(env, ARM_FEATURE_XSCALE) + && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum))) + return 1; + + switch (cpnum) { + case 0: + case 1: + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + return disas_iwmmxt_insn(env, s, insn); + } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { + return disas_dsp_insn(env, s, insn); + } + return 1; + case 10: + case 11: + return disas_vfp_insn (env, s, insn); + case 14: + /* Coprocessors 7-15 are architecturally reserved by ARM. + Unfortunately Intel decided to ignore this. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto board; + if (insn & (1 << 20)) + return disas_cp14_read(env, s, insn); + else + return disas_cp14_write(env, s, insn); + case 15: + return disas_cp15_insn (env, s, insn); + default: + board: + /* Unknown coprocessor. See if the board has hooked it. */ + return disas_cp_insn (env, s, insn); + } +} + + +/* Store a 64-bit value to a register pair. Clobbers val. */ +static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rlow, tmp); + tmp = new_tmp(); + tcg_gen_shri_i64(val, val, 32); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rhigh, tmp); +} + +/* load a 32-bit value from a register and perform a 64-bit accumulate. */ +static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow) +{ + TCGv_i64 tmp; + TCGv tmp2; + + /* Load value and extend to 64 bits. */ + tmp = tcg_temp_new_i64(); + tmp2 = load_reg(s, rlow); + tcg_gen_extu_i32_i64(tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* load and add a 64-bit value from a register pair. */ +static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) +{ + TCGv_i64 tmp; + TCGv tmpl; + TCGv tmph; + + /* Load 64-bit value rd:rn. */ + tmpl = load_reg(s, rlow); + tmph = load_reg(s, rhigh); + tmp = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(tmp, tmpl, tmph); + dead_tmp(tmpl); + dead_tmp(tmph); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* Set N and Z flags from a 64-bit value. */ +static void gen_logicq_cc(TCGv_i64 val) +{ + TCGv tmp = new_tmp(); + gen_helper_logicq_cc(tmp, val); + gen_logic_CC(tmp); + dead_tmp(tmp); +} + +/* Load/Store exclusive instructions are implemented by remembering + the value/address loaded, and seeing if these are the same + when the store is performed. This should be is sufficient to implement + the architecturally mandated semantics, and avoids having to monitor + regular stores. + + In system emulation mode only one CPU will be running at once, so + this sequence is effectively atomic. In user emulation mode we + throw an exception and handle the atomic operation elsewhere. */ +static void gen_load_exclusive(DisasContext *s, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_mov_i32(cpu_exclusive_val, tmp); + store_reg(s, rt, tmp); + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + tcg_gen_mov_i32(cpu_exclusive_high, tmp); + store_reg(s, rt2, tmp); + } + tcg_gen_mov_i32(cpu_exclusive_addr, addr); +} + +static void gen_clrex(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} + +#ifdef CONFIG_USER_ONLY +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + tcg_gen_mov_i32(cpu_exclusive_test, addr); + tcg_gen_movi_i32(cpu_exclusive_info, + size | (rd << 4) | (rt << 8) | (rt2 << 12)); + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_STREX); + s->is_jmp = DISAS_JUMP; +} +#else +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + int done_label; + int fail_label; + + /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) { + [addr] = {Rt}; + {Rd} = 0; + } else { + {Rd} = 1; + } */ + fail_label = gen_new_label(); + done_label = gen_new_label(); + tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label); + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label); + dead_tmp(tmp); + if (size == 3) { + TCGv tmp2 = new_tmp(); + tcg_gen_addi_i32(tmp2, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(tmp2); + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label); + dead_tmp(tmp); + } + tmp = load_reg(s, rt); + switch (size) { + case 0: + gen_st8(tmp, addr, IS_USER(s)); + break; + case 1: + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: + case 3: + gen_st32(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rt2); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_movi_i32(cpu_R[rd], 0); + tcg_gen_br(done_label); + gen_set_label(fail_label); + tcg_gen_movi_i32(cpu_R[rd], 1); + gen_set_label(done_label); + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} +#endif + +static void disas_arm_insn(CPUState * env, DisasContext *s) +{ + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; + TCGv_i64 tmp64; + + insn = ldl_code(s->pc); + s->pc += 4; + + /* M variants do not implement ARM mode. */ + if (IS_M(env)) + goto illegal_op; + cond = insn >> 28; + if (cond == 0xf){ + /* Unconditional instructions. */ + if (((insn >> 25) & 7) == 1) { + /* NEON Data processing. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0f100000) == 0x04000000) { + /* NEON load/store. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_ls_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0d70f000) == 0x0550f000) + return; /* PLD */ + else if ((insn & 0x0ffffdff) == 0x01010000) { + ARCH(6); + /* setend */ + if (insn & (1 << 9)) { + /* BE8 mode not implemented. */ + goto illegal_op; + } + return; + } else if ((insn & 0x0fffff00) == 0x057ff000) { + switch ((insn >> 4) & 0xf) { + case 1: /* clrex */ + ARCH(6K); + gen_clrex(s); + return; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + ARCH(7); + /* We don't emulate caches so these are a no-op. */ + return; + default: + goto illegal_op; + } + } else if ((insn & 0x0e5fffe0) == 0x084d0500) { + /* srs */ + int32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + op1 = (insn & 0x1f); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + addr = load_reg(s, 13); + } else { + addr = new_tmp(); + tmp = tcg_const_i32(op1); + gen_helper_get_r13_banked(addr, cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = -4; break; /* DA */ + case 1: offset = 0; break; /* IA */ + case 2: offset = -8; break; /* DB */ + case 3: offset = 4; break; /* IB */ + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tmp = load_cpu_field(spsr); + tcg_gen_addi_i32(addr, addr, 4); + gen_st32(tmp, addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -8; break; + case 1: offset = 4; break; + case 2: offset = -4; break; + case 3: offset = 0; break; + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + store_reg(s, 13, addr); + } else { + tmp = tcg_const_i32(op1); + gen_helper_set_r13_banked(cpu_env, tmp, addr); + tcg_temp_free_i32(tmp); + dead_tmp(addr); + } + } else { + dead_tmp(addr); + } + } else if ((insn & 0x0e5fffe0) == 0x081d0a00) { + /* rfe */ + int32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + rn = (insn >> 16) & 0xf; + addr = load_reg(s, rn); + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = -4; break; /* DA */ + case 1: offset = 0; break; /* IA */ + case 2: offset = -8; break; /* DB */ + case 3: offset = 4; break; /* IB */ + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -8; break; + case 1: offset = 4; break; + case 2: offset = -4; break; + case 3: offset = 0; break; + default: abort(); + } + if (offset) + tcg_gen_addi_i32(addr, addr, offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + gen_rfe(s, tmp, tmp2); + return; + } else if ((insn & 0x0e000000) == 0x0a000000) { + /* branch link and change to thumb (blx ) */ + int32_t offset; + + val = (uint32_t)s->pc; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); + /* Sign-extend the 24-bit offset */ + offset = (((int32_t)insn) << 8) >> 8; + /* offset * 4 + bit24 * 2 + (thumb bit) */ + val += (offset << 2) | ((insn >> 23) & 2) | 1; + /* pipeline offset */ + val += 4; + gen_bx_im(s, val); + return; + } else if ((insn & 0x0e000f00) == 0x0c000100) { + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + /* iWMMXt register transfer. */ + if (env->cp15.c15_cpar & (1 << 1)) + if (!disas_iwmmxt_insn(env, s, insn)) + return; + } + } else if ((insn & 0x0fe00000) == 0x0c400000) { + /* Coprocessor double register transfer. */ + } else if ((insn & 0x0f000010) == 0x0e000010) { + /* Additional coprocessor register transfer. */ + } else if ((insn & 0x0ff10020) == 0x01000000) { + uint32_t mask; + uint32_t val; + /* cps (privileged) */ + if (IS_USER(s)) + return; + mask = val = 0; + if (insn & (1 << 19)) { + if (insn & (1 << 8)) + mask |= CPSR_A; + if (insn & (1 << 7)) + mask |= CPSR_I; + if (insn & (1 << 6)) + mask |= CPSR_F; + if (insn & (1 << 18)) + val |= mask; + } + if (insn & (1 << 17)) { + mask |= CPSR_M; + val |= (insn & 0x1f); + } + if (mask) { + gen_set_psr_im(s, mask, 0, val); + } + return; + } + goto illegal_op; + } + if (cond != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + } + if ((insn & 0x0f900000) == 0x03000000) { + if ((insn & (1 << 21)) == 0) { + ARCH(6T2); + rd = (insn >> 12) & 0xf; + val = ((insn >> 4) & 0xf000) | (insn & 0xfff); + if ((insn & (1 << 22)) == 0) { + /* MOVW */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else { + /* MOVT */ + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, val << 16); + } + store_reg(s, rd, tmp); + } else { + if (((insn >> 12) & 0xf) != 0xf) + goto illegal_op; + if (((insn >> 16) & 0xf) == 0) { + gen_nop_hint(s, insn & 0xff); + } else { + /* CPSR = immediate */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + i = ((insn & (1 << 22)) != 0); + if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val)) + goto illegal_op; + } + } + } else if ((insn & 0x0f900000) == 0x01000000 + && (insn & 0x00000090) != 0x00000090) { + /* miscellaneous instructions */ + op1 = (insn >> 21) & 3; + sh = (insn >> 4) & 0xf; + rm = insn & 0xf; + switch (sh) { + case 0x0: /* move program status register */ + if (op1 & 1) { + /* PSR = reg */ + tmp = load_reg(s, rm); + i = ((op1 & 2) != 0); + if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp)) + goto illegal_op; + } else { + /* reg = PSR */ + rd = (insn >> 12) & 0xf; + if (op1 & 2) { + if (IS_USER(s)) + goto illegal_op; + tmp = load_cpu_field(spsr); + } else { + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + } + store_reg(s, rd, tmp); + } + break; + case 0x1: + if (op1 == 1) { + /* branch/exchange thumb (bx). */ + tmp = load_reg(s, rm); + gen_bx(s, tmp); + } else if (op1 == 3) { + /* clz */ + rd = (insn >> 12) & 0xf; + tmp = load_reg(s, rm); + gen_helper_clz(tmp, tmp); + store_reg(s, rd, tmp); + } else { + goto illegal_op; + } + break; + case 0x2: + if (op1 == 1) { + ARCH(5J); /* bxj */ + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, rm); + gen_bx(s, tmp); + } else { + goto illegal_op; + } + break; + case 0x3: + if (op1 != 1) + goto illegal_op; + + /* branch link/exchange thumb (blx) */ + tmp = load_reg(s, rm); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + break; + case 0x5: /* saturating add/subtract */ + rd = (insn >> 12) & 0xf; + rn = (insn >> 16) & 0xf; + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rn); + if (op1 & 2) + gen_helper_double_saturate(tmp2, tmp2); + if (op1 & 1) + gen_helper_sub_saturate(tmp, tmp, tmp2); + else + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 7: /* bkpt */ + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_BKPT); + s->is_jmp = DISAS_JUMP; + break; + case 0x8: /* signed multiply */ + case 0xa: + case 0xc: + case 0xe: + rs = (insn >> 8) & 0xf; + rn = (insn >> 12) & 0xf; + rd = (insn >> 16) & 0xf; + if (op1 == 1) { + /* (32 * 16) >> 16 */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + if (sh & 4) + tcg_gen_sari_i32(tmp2, tmp2, 16); + else + gen_sxth(tmp2); + tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp64, tmp64, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if ((sh & 2) == 0) { + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + } else { + /* 16 * 16 */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_mulxy(tmp, tmp2, sh & 2, sh & 4); + dead_tmp(tmp2); + if (op1 == 2) { + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rn, rd); + gen_storeq_reg(s, rn, rd, tmp64); + tcg_temp_free_i64(tmp64); + } else { + if (op1 == 0) { + tmp2 = load_reg(s, rn); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + } + } + break; + default: + goto illegal_op; + } + } else if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { + int set_cc, logic_cc, shiftop; + + op1 = (insn >> 21) & 0xf; + set_cc = (insn >> 20) & 1; + logic_cc = table_logic_cc[op1] & set_cc; + + /* data processing instruction */ + if (insn & (1 << 25)) { + /* immediate operand */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) { + val = (val >> shift) | (val << (32 - shift)); + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + if (logic_cc && shift) { + gen_set_CF_bit31(tmp2); + } + } else { + /* register */ + rm = (insn) & 0xf; + tmp2 = load_reg(s, rm); + shiftop = (insn >> 5) & 3; + if (!(insn & (1 << 4))) { + shift = (insn >> 7) & 0x1f; + gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); + } else { + rs = (insn >> 8) & 0xf; + tmp = load_reg(s, rs); + gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc); + } + } + if (op1 != 0x0f && op1 != 0x0d) { + rn = (insn >> 16) & 0xf; + tmp = load_reg(s, rn); + } else { + TCGV_UNUSED(tmp); + } + rd = (insn >> 12) & 0xf; + switch(op1) { + case 0x00: + tcg_gen_and_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x01: + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x02: + if (set_cc && rd == 15) { + /* SUBS r15, ... is used for exception return. */ + if (IS_USER(s)) { + goto illegal_op; + } + gen_helper_sub_cc(tmp, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (set_cc) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + } + break; + case 0x03: + if (set_cc) { + gen_helper_sub_cc(tmp, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x04: + if (set_cc) { + gen_helper_add_cc(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x05: + if (set_cc) { + gen_helper_adc_cc(tmp, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x06: + if (set_cc) { + gen_helper_sbc_cc(tmp, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x07: + if (set_cc) { + gen_helper_sbc_cc(tmp, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x08: + if (set_cc) { + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x09: + if (set_cc) { + tcg_gen_xor_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x0a: + if (set_cc) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0b: + if (set_cc) { + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0c: + tcg_gen_or_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + case 0x0d: + if (logic_cc && rd == 15) { + /* MOVS r15, ... is used for exception return. */ + if (IS_USER(s)) { + goto illegal_op; + } + gen_exception_return(s, tmp2); + } else { + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(env, s, rd, tmp2); + } + break; + case 0x0e: + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(env, s, rd, tmp); + break; + default: + case 0x0f: + tcg_gen_not_i32(tmp2, tmp2); + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(env, s, rd, tmp2); + break; + } + if (op1 != 0x0f && op1 != 0x0d) { + dead_tmp(tmp2); + } + } else { + /* other instructions */ + op1 = (insn >> 24) & 0xf; + switch(op1) { + case 0x0: + case 0x1: + /* multiplies, extra load/stores */ + sh = (insn >> 5) & 3; + if (sh == 0) { + if (op1 == 0x0) { + rd = (insn >> 16) & 0xf; + rn = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + rm = (insn) & 0xf; + op1 = (insn >> 20) & 0xf; + switch (op1) { + case 0: case 1: case 2: case 3: case 6: + /* 32 bit mul */ + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (insn & (1 << 22)) { + /* Subtract (mls) */ + ARCH(6T2); + tmp2 = load_reg(s, rn); + tcg_gen_sub_i32(tmp, tmp2, tmp); + dead_tmp(tmp2); + } else if (insn & (1 << 21)) { + /* Add */ + tmp2 = load_reg(s, rn); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + if (insn & (1 << 20)) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + break; + default: + /* 64 bit mul */ + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + if (insn & (1 << 22)) + tmp64 = gen_muls_i64_i32(tmp, tmp2); + else + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + if (insn & (1 << 21)) /* mult accumulate */ + gen_addq(s, tmp64, rn, rd); + if (!(insn & (1 << 23))) { /* double accumulate */ + ARCH(6); + gen_addq_lo(s, tmp64, rn); + gen_addq_lo(s, tmp64, rd); + } + if (insn & (1 << 20)) + gen_logicq_cc(tmp64); + gen_storeq_reg(s, rn, rd, tmp64); + tcg_temp_free_i64(tmp64); + break; + } + } else { + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (insn & (1 << 23)) { + /* load/store exclusive */ + op1 = (insn >> 21) & 0x3; + if (op1) + ARCH(6K); + else + ARCH(6); + addr = tcg_temp_local_new_i32(); + load_reg_var(s, addr, rn); + if (insn & (1 << 20)) { + switch (op1) { + case 0: /* ldrex */ + gen_load_exclusive(s, rd, 15, addr, 2); + break; + case 1: /* ldrexd */ + gen_load_exclusive(s, rd, rd + 1, addr, 3); + break; + case 2: /* ldrexb */ + gen_load_exclusive(s, rd, 15, addr, 0); + break; + case 3: /* ldrexh */ + gen_load_exclusive(s, rd, 15, addr, 1); + break; + default: + abort(); + } + } else { + rm = insn & 0xf; + switch (op1) { + case 0: /* strex */ + gen_store_exclusive(s, rd, rm, 15, addr, 2); + break; + case 1: /* strexd */ + gen_store_exclusive(s, rd, rm, rm + 1, addr, 3); + break; + case 2: /* strexb */ + gen_store_exclusive(s, rd, rm, 15, addr, 0); + break; + case 3: /* strexh */ + gen_store_exclusive(s, rd, rm, 15, addr, 1); + break; + default: + abort(); + } + } + tcg_temp_free(addr); + } else { + /* SWP instruction */ + rm = (insn) & 0xf; + + /* ??? This is not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ + addr = load_reg(s, rn); + tmp = load_reg(s, rm); + if (insn & (1 << 22)) { + tmp2 = gen_ld8u(addr, IS_USER(s)); + gen_st8(tmp, addr, IS_USER(s)); + } else { + tmp2 = gen_ld32(addr, IS_USER(s)); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + store_reg(s, rd, tmp2); + } + } + } else { + int address_offset; + int load; + /* Misc load/store */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + addr = load_reg(s, rn); + if (insn & (1 << 24)) + gen_add_datah_offset(s, insn, 0, addr); + address_offset = 0; + if (insn & (1 << 20)) { + /* load */ + switch(sh) { + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld8s(addr, IS_USER(s)); + break; + default: + case 3: + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + load = 1; + } else if (sh & 2) { + /* doubleword */ + if (sh & 1) { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd + 1); + gen_st32(tmp, addr, IS_USER(s)); + load = 0; + } else { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + rd++; + load = 1; + } + address_offset = -4; + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); + load = 0; + } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. + ldrd with base writeback is is undefined if the + destination and index registers overlap. */ + if (!(insn & (1 << 24))) { + gen_add_datah_offset(s, insn, address_offset, addr); + store_reg(s, rn, addr); + } else if (insn & (1 << 21)) { + if (address_offset) + tcg_gen_addi_i32(addr, addr, address_offset); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + if (load) { + /* Complete the load. */ + store_reg(s, rd, tmp); + } + } + break; + case 0x4: + case 0x5: + goto do_ldst; + case 0x6: + case 0x7: + if (insn & (1 << 4)) { + ARCH(6); + /* Armv6 Media instructions. */ + rm = insn & 0xf; + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + switch ((insn >> 23) & 3) { + case 0: /* Parallel add/subtract. */ + op1 = (insn >> 20) & 7; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + sh = (insn >> 5) & 7; + if ((op1 & 3) == 0 || sh == 5 || sh == 6) + goto illegal_op; + gen_arm_parallel_addsub(op1, sh, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 1: + if ((insn & 0x00700020) == 0) { + /* Halfword pack. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (insn & (1 << 6)) { + /* pkhtb */ + if (shift == 0) + shift = 31; + tcg_gen_sari_i32(tmp2, tmp2, shift); + tcg_gen_andi_i32(tmp, tmp, 0xffff0000); + tcg_gen_ext16u_i32(tmp2, tmp2); + } else { + /* pkhbt */ + if (shift) + tcg_gen_shli_i32(tmp2, tmp2, shift); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000); + } + tcg_gen_or_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x00200020) == 0x00200000) { + /* [us]sat */ + tmp = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (insn & (1 << 6)) { + if (shift == 0) + shift = 31; + tcg_gen_sari_i32(tmp, tmp, shift); + } else { + tcg_gen_shli_i32(tmp, tmp, shift); + } + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) + gen_helper_usat(tmp, tmp, tmp2); + else + gen_helper_ssat(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); + } else if ((insn & 0x00300fe0) == 0x00200f20) { + /* [us]sat16 */ + tmp = load_reg(s, rm); + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) + gen_helper_usat16(tmp, tmp, tmp2); + else + gen_helper_ssat16(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); + } else if ((insn & 0x00700fe0) == 0x00000fa0) { + /* Select bytes. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x000003e0) == 0x00000060) { + tmp = load_reg(s, rm); + shift = (insn >> 10) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + tcg_gen_rotri_i32(tmp, tmp, shift * 8); + op1 = (insn >> 20) & 7; + switch (op1) { + case 0: gen_sxtb16(tmp); break; + case 2: gen_sxtb(tmp); break; + case 3: gen_sxth(tmp); break; + case 4: gen_uxtb16(tmp); break; + case 6: gen_uxtb(tmp); break; + case 7: gen_uxth(tmp); break; + default: goto illegal_op; + } + if (rn != 15) { + tmp2 = load_reg(s, rn); + if ((op1 & 3) == 0) { + gen_add16(tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + } + store_reg(s, rd, tmp); + } else if ((insn & 0x003f0f60) == 0x003f0f20) { + /* rev */ + tmp = load_reg(s, rm); + if (insn & (1 << 22)) { + if (insn & (1 << 7)) { + gen_revsh(tmp); + } else { + ARCH(6T2); + gen_helper_rbit(tmp, tmp); + } + } else { + if (insn & (1 << 7)) + gen_rev16(tmp); + else + tcg_gen_bswap32_i32(tmp, tmp); + } + store_reg(s, rd, tmp); + } else { + goto illegal_op; + } + break; + case 2: /* Multiplies (Type 3). */ + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + if (insn & (1 << 20)) { + /* Signed multiply most significant [accumulate]. */ + tmp64 = gen_muls_i64_i32(tmp, tmp2); + if (insn & (1 << 5)) + tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u); + tcg_gen_shri_i64(tmp64, tmp64, 32); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if (rd != 15) { + tmp2 = load_reg(s, rd); + if (insn & (1 << 6)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + } else { + if (insn & (1 << 5)) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + /* This addition cannot overflow. */ + if (insn & (1 << 6)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + if (insn & (1 << 22)) { + /* smlald, smlsld */ + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rd, rn); + gen_storeq_reg(s, rd, rn, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* smuad, smusd, smlad, smlsd */ + if (rd != 15) + { + tmp2 = load_reg(s, rd); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + } + } + break; + case 3: + op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); + switch (op1) { + case 0: /* Unsigned sum of absolute differences. */ + ARCH(6); + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rs); + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rd != 15) { + tmp2 = load_reg(s, rd); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + store_reg(s, rn, tmp); + break; + case 0x20: case 0x24: case 0x28: case 0x2c: + /* Bitfield insert/clear. */ + ARCH(6T2); + shift = (insn >> 7) & 0x1f; + i = (insn >> 16) & 0x1f; + i = i + 1 - shift; + if (rm == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rm); + } + if (i != 32) { + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1); + dead_tmp(tmp2); + } + store_reg(s, rd, tmp); + break; + case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ + case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ + ARCH(6T2); + tmp = load_reg(s, rm); + shift = (insn >> 7) & 0x1f; + i = ((insn >> 16) & 0x1f) + 1; + if (shift + i > 32) + goto illegal_op; + if (i < 32) { + if (op1 & 0x20) { + gen_ubfx(tmp, shift, (1u << i) - 1); + } else { + gen_sbfx(tmp, shift, i); + } + } + store_reg(s, rd, tmp); + break; + default: + goto illegal_op; + } + break; + } + break; + } + do_ldst: + /* Check for undefined extension instructions + * per the ARM Bible IE: + * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + */ + sh = (0xf << 20) | (0xf << 4); + if (op1 == 0x7 && ((insn & sh) == sh)) + { + goto illegal_op; + } + /* load/store byte/word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + tmp2 = load_reg(s, rn); + i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); + if (insn & (1 << 24)) + gen_add_data_offset(s, insn, tmp2); + if (insn & (1 << 20)) { + /* load */ + if (insn & (1 << 22)) { + tmp = gen_ld8u(tmp2, i); + } else { + tmp = gen_ld32(tmp2, i); + } + } else { + /* store */ + tmp = load_reg(s, rd); + if (insn & (1 << 22)) + gen_st8(tmp, tmp2, i); + else + gen_st32(tmp, tmp2, i); + } + if (!(insn & (1 << 24))) { + gen_add_data_offset(s, insn, tmp2); + store_reg(s, rn, tmp2); + } else if (insn & (1 << 21)) { + store_reg(s, rn, tmp2); + } else { + dead_tmp(tmp2); + } + if (insn & (1 << 20)) { + /* Complete the load. */ + if (rd == 15) + gen_bx(s, tmp); + else + store_reg(s, rd, tmp); + } + break; + case 0x08: + case 0x09: + { + int j, n, user, loaded_base; + TCGv loaded_var; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + user = 0; + if (insn & (1 << 22)) { + if (IS_USER(s)) + goto illegal_op; /* only usable in supervisor mode */ + + if ((insn & (1 << 15)) == 0) + user = 1; + } + rn = (insn >> 16) & 0xf; + addr = load_reg(s, rn); + + /* compute total size */ + loaded_base = 0; + TCGV_UNUSED(loaded_var); + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* post increment */ + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { + /* post decrement */ + if (n != 1) + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + if (i == 15) { + gen_bx(s, tmp); + } else if (user) { + tmp2 = tcg_const_i32(i); + gen_helper_set_user_reg(tmp2, tmp); + tcg_temp_free_i32(tmp2); + dead_tmp(tmp); + } else if (i == rn) { + loaded_var = tmp; + loaded_base = 1; + } else { + store_reg(s, i, tmp); + } + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 8 */ + val = (long)s->pc + 4; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else if (user) { + tmp = new_tmp(); + tmp2 = tcg_const_i32(i); + gen_helper_get_user_reg(tmp, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, i); + } + gen_st32(tmp, addr, IS_USER(s)); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + tcg_gen_addi_i32(addr, addr, 4); + } + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + if (loaded_base) { + store_reg(s, rn, loaded_var); + } + if ((insn & (1 << 22)) && !user) { + /* Restore CPSR from SPSR. */ + tmp = load_cpu_field(spsr); + gen_set_cpsr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; + } + } + break; + case 0xa: + case 0xb: + { + int32_t offset; + + /* branch (and link) */ + val = (int32_t)s->pc; + if (insn & (1 << 24)) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 14, tmp); + } + offset = (((int32_t)insn << 8) >> 8); + val += (offset << 2) + 4; + gen_jmp(s, val); + } + break; + case 0xc: + case 0xd: + case 0xe: + /* Coprocessor. */ + if (disas_coproc_insn(env, s, insn)) + goto illegal_op; + break; + case 0xf: + /* swi */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SWI; + break; + default: + illegal_op: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; + break; + } + } +} + +/* Return true if this is a Thumb-2 logical op. */ +static int +thumb2_logic_op(int op) +{ + return (op < 8); +} + +/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero + then set condition code flags based on the result of the operation. + If SHIFTER_OUT is nonzero then set the carry flag for logical operations + to the high bit of T1. + Returns zero if the opcode is valid. */ + +static int +gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1) +{ + int logic_cc; + + logic_cc = 0; + switch (op) { + case 0: /* and */ + tcg_gen_and_i32(t0, t0, t1); + logic_cc = conds; + break; + case 1: /* bic */ + tcg_gen_andc_i32(t0, t0, t1); + logic_cc = conds; + break; + case 2: /* orr */ + tcg_gen_or_i32(t0, t0, t1); + logic_cc = conds; + break; + case 3: /* orn */ + tcg_gen_not_i32(t1, t1); + tcg_gen_or_i32(t0, t0, t1); + logic_cc = conds; + break; + case 4: /* eor */ + tcg_gen_xor_i32(t0, t0, t1); + logic_cc = conds; + break; + case 8: /* add */ + if (conds) + gen_helper_add_cc(t0, t0, t1); + else + tcg_gen_add_i32(t0, t0, t1); + break; + case 10: /* adc */ + if (conds) + gen_helper_adc_cc(t0, t0, t1); + else + gen_adc(t0, t1); + break; + case 11: /* sbc */ + if (conds) + gen_helper_sbc_cc(t0, t0, t1); + else + gen_sub_carry(t0, t0, t1); + break; + case 13: /* sub */ + if (conds) + gen_helper_sub_cc(t0, t0, t1); + else + tcg_gen_sub_i32(t0, t0, t1); + break; + case 14: /* rsb */ + if (conds) + gen_helper_sub_cc(t0, t1, t0); + else + tcg_gen_sub_i32(t0, t1, t0); + break; + default: /* 5, 6, 7, 9, 12, 15. */ + return 1; + } + if (logic_cc) { + gen_logic_CC(t0); + if (shifter_out) + gen_set_CF_bit31(t1); + } + return 0; +} + +/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction + is not legal. */ +static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) +{ + uint32_t insn, imm, shift, offset; + uint32_t rd, rn, rm, rs; + TCGv tmp; + TCGv tmp2; + TCGv tmp3; + TCGv addr; + TCGv_i64 tmp64; + int op; + int shiftop; + int conds; + int logic_cc; + + if (!(arm_feature(env, ARM_FEATURE_THUMB2) + || arm_feature (env, ARM_FEATURE_M))) { + /* Thumb-1 cores may need to treat bl and blx as a pair of + 16-bit instructions to get correct prefetch abort behavior. */ + insn = insn_hw1; + if ((insn & (1 << 12)) == 0) { + /* Second half of blx. */ + offset = ((insn & 0x7ff) << 1); + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); + tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); + + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + return 0; + } + if (insn & (1 << 11)) { + /* Second half of bl. */ + offset = ((insn & 0x7ff) << 1) | 1; + tmp = load_reg(s, 14); + tcg_gen_addi_i32(tmp, tmp, offset); + + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, s->pc | 1); + store_reg(s, 14, tmp2); + gen_bx(s, tmp); + return 0; + } + if ((s->pc & ~TARGET_PAGE_MASK) == 0) { + /* Instruction spans a page boundary. Implement it as two + 16-bit instructions in case the second half causes an + prefetch abort. */ + offset = ((int32_t)insn << 21) >> 9; + tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset); + return 0; + } + /* Fall through to 32-bit decode. */ + } + + insn = lduw_code(s->pc); + s->pc += 2; + insn |= (uint32_t)insn_hw1 << 16; + + if ((insn & 0xf800e800) != 0xf000e800) { + ARCH(6T2); + } + + rn = (insn >> 16) & 0xf; + rs = (insn >> 12) & 0xf; + rd = (insn >> 8) & 0xf; + rm = insn & 0xf; + switch ((insn >> 25) & 0xf) { + case 0: case 1: case 2: case 3: + /* 16-bit instructions. Should never happen. */ + abort(); + case 4: + if (insn & (1 << 22)) { + /* Other load/store, table branch. */ + if (insn & 0x01200000) { + /* Load/store doubleword. */ + if (rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc & ~3); + } else { + addr = load_reg(s, rn); + } + offset = (insn & 0xff) * 4; + if ((insn & (1 << 23)) == 0) + offset = -offset; + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, offset); + offset = 0; + } + if (insn & (1 << 20)) { + /* ldrd */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rs, tmp); + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* strd */ + tmp = load_reg(s, rs); + gen_st32(tmp, addr, IS_USER(s)); + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + if (insn & (1 << 21)) { + /* Base writeback. */ + if (rn == 15) + goto illegal_op; + tcg_gen_addi_i32(addr, addr, offset - 4); + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } else if ((insn & (1 << 23)) == 0) { + /* Load/store exclusive word. */ + addr = tcg_temp_local_new(); + load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2); + if (insn & (1 << 20)) { + gen_load_exclusive(s, rs, 15, addr, 2); + } else { + gen_store_exclusive(s, rd, rs, 15, addr, 2); + } + tcg_temp_free(addr); + } else if ((insn & (1 << 6)) == 0) { + /* Table Branch. */ + if (rn == 15) { + addr = new_tmp(); + tcg_gen_movi_i32(addr, s->pc); + } else { + addr = load_reg(s, rn); + } + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); + if (insn & (1 << 4)) { + /* tbh */ + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + tmp = gen_ld16u(addr, IS_USER(s)); + } else { /* tbb */ + dead_tmp(tmp); + tmp = gen_ld8u(addr, IS_USER(s)); + } + dead_tmp(addr); + tcg_gen_shli_i32(tmp, tmp, 1); + tcg_gen_addi_i32(tmp, tmp, s->pc); + store_reg(s, 15, tmp); + } else { + /* Load/store exclusive byte/halfword/doubleword. */ + ARCH(7); + op = (insn >> 4) & 0x3; + if (op == 2) { + goto illegal_op; + } + addr = tcg_temp_local_new(); + load_reg_var(s, addr, rn); + if (insn & (1 << 20)) { + gen_load_exclusive(s, rs, rd, addr, op); + } else { + gen_store_exclusive(s, rm, rs, rd, addr, op); + } + tcg_temp_free(addr); + } + } else { + /* Load/store multiple, RFE, SRS. */ + if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { + /* Not available in user mode. */ + if (IS_USER(s)) + goto illegal_op; + if (insn & (1 << 20)) { + /* rfe */ + addr = load_reg(s, rn); + if ((insn & (1 << 24)) == 0) + tcg_gen_addi_i32(addr, addr, -8); + /* Load PC into tmp and CPSR into tmp2. */ + tmp = gen_ld32(addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp2 = gen_ld32(addr, 0); + if (insn & (1 << 21)) { + /* Base writeback. */ + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, 4); + } else { + tcg_gen_addi_i32(addr, addr, -4); + } + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + gen_rfe(s, tmp, tmp2); + } else { + /* srs */ + op = (insn & 0x1f); + if (op == (env->uncached_cpsr & CPSR_M)) { + addr = load_reg(s, 13); + } else { + addr = new_tmp(); + tmp = tcg_const_i32(op); + gen_helper_get_r13_banked(addr, cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + if ((insn & (1 << 24)) == 0) { + tcg_gen_addi_i32(addr, addr, -8); + } + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp = new_tmp(); + gen_helper_cpsr_read(tmp); + gen_st32(tmp, addr, 0); + if (insn & (1 << 21)) { + if ((insn & (1 << 24)) == 0) { + tcg_gen_addi_i32(addr, addr, -4); + } else { + tcg_gen_addi_i32(addr, addr, 4); + } + if (op == (env->uncached_cpsr & CPSR_M)) { + store_reg(s, 13, addr); + } else { + tmp = tcg_const_i32(op); + gen_helper_set_r13_banked(cpu_env, tmp, addr); + tcg_temp_free_i32(tmp); + } + } else { + dead_tmp(addr); + } + } + } else { + int i; + /* Load/store multiple. */ + addr = load_reg(s, rn); + offset = 0; + for (i = 0; i < 16; i++) { + if (insn & (1 << i)) + offset += 4; + } + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, -offset); + } + + for (i = 0; i < 16; i++) { + if ((insn & (1 << i)) == 0) + continue; + if (insn & (1 << 20)) { + /* Load. */ + tmp = gen_ld32(addr, IS_USER(s)); + if (i == 15) { + gen_bx(s, tmp); + } else { + store_reg(s, i, tmp); + } + } else { + /* Store. */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, 4); + } + if (insn & (1 << 21)) { + /* Base register writeback. */ + if (insn & (1 << 24)) { + tcg_gen_addi_i32(addr, addr, -offset); + } + /* Fault if writeback register is in register list. */ + if (insn & (1 << rn)) + goto illegal_op; + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + } + break; + case 5: /* Data processing register constant shift. */ + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + tmp2 = load_reg(s, rm); + op = (insn >> 21) & 0xf; + shiftop = (insn >> 4) & 3; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + conds = (insn & (1 << 20)) != 0; + logic_cc = (conds && thumb2_logic_op(op)); + gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); + if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2)) + goto illegal_op; + dead_tmp(tmp2); + if (rd != 15) { + store_reg(s, rd, tmp); + } else { + dead_tmp(tmp); + } + break; + case 13: /* Misc data processing. */ + op = ((insn >> 22) & 6) | ((insn >> 7) & 1); + if (op < 4 && (insn & 0xf000) != 0xf000) + goto illegal_op; + switch (op) { + case 0: /* Register controlled shift. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if ((insn & 0x70) != 0) + goto illegal_op; + op = (insn >> 21) & 3; + logic_cc = (insn & (1 << 20)) != 0; + gen_arm_shift_reg(tmp, op, tmp2, logic_cc); + if (logic_cc) + gen_logic_CC(tmp); + store_reg_bx(env, s, rd, tmp); + break; + case 1: /* Sign/zero extend. */ + tmp = load_reg(s, rm); + shift = (insn >> 4) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + tcg_gen_rotri_i32(tmp, tmp, shift * 8); + op = (insn >> 20) & 7; + switch (op) { + case 0: gen_sxth(tmp); break; + case 1: gen_uxth(tmp); break; + case 2: gen_sxtb16(tmp); break; + case 3: gen_uxtb16(tmp); break; + case 4: gen_sxtb(tmp); break; + case 5: gen_uxtb(tmp); break; + default: goto illegal_op; + } + if (rn != 15) { + tmp2 = load_reg(s, rn); + if ((op >> 1) == 1) { + gen_add16(tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + } + store_reg(s, rd, tmp); + break; + case 2: /* SIMD add/subtract. */ + op = (insn >> 20) & 7; + shift = (insn >> 4) & 7; + if ((op & 3) == 3 || (shift & 3) == 3) + goto illegal_op; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + gen_thumb2_parallel_addsub(op, shift, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 3: /* Other data processing. */ + op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); + if (op < 4) { + /* Saturating add/subtract. */ + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if (op & 2) + gen_helper_double_saturate(tmp, tmp); + if (op & 1) + gen_helper_sub_saturate(tmp, tmp2, tmp); + else + gen_helper_add_saturate(tmp, tmp, tmp2); + dead_tmp(tmp2); + } else { + tmp = load_reg(s, rn); + switch (op) { + case 0x0a: /* rbit */ + gen_helper_rbit(tmp, tmp); + break; + case 0x08: /* rev */ + tcg_gen_bswap32_i32(tmp, tmp); + break; + case 0x09: /* rev16 */ + gen_rev16(tmp); + break; + case 0x0b: /* revsh */ + gen_revsh(tmp); + break; + case 0x10: /* sel */ + tmp2 = load_reg(s, rm); + tmp3 = new_tmp(); + tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE)); + gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); + dead_tmp(tmp3); + dead_tmp(tmp2); + break; + case 0x18: /* clz */ + gen_helper_clz(tmp, tmp); + break; + default: + goto illegal_op; + } + } + store_reg(s, rd, tmp); + break; + case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ + op = (insn >> 4) & 0xf; + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + switch ((insn >> 20) & 7) { + case 0: /* 32 x 32 -> 32 */ + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + if (op) + tcg_gen_sub_i32(tmp, tmp2, tmp); + else + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 1: /* 16 x 16 -> 32 */ + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 2: /* Dual multiply add. */ + case 4: /* Dual multiply subtract. */ + if (op) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + /* This addition cannot overflow. */ + if (insn & (1 << 22)) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + if (rs != 15) + { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 3: /* 32 * 16 -> 32msb */ + if (op) + tcg_gen_sari_i32(tmp2, tmp2, 16); + else + gen_sxth(tmp2); + tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_shri_i64(tmp64, tmp64, 16); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + if (rs != 15) + { + tmp2 = load_reg(s, rs); + gen_helper_add_setq(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + case 5: case 6: /* 32 * 32 -> 32msb */ + gen_imull(tmp, tmp2); + if (insn & (1 << 5)) { + gen_roundqd(tmp, tmp2); + dead_tmp(tmp2); + } else { + dead_tmp(tmp); + tmp = tmp2; + } + if (rs != 15) { + tmp2 = load_reg(s, rs); + if (insn & (1 << 21)) { + tcg_gen_add_i32(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + dead_tmp(tmp2); + } + break; + case 7: /* Unsigned sum of absolute differences. */ + gen_helper_usad8(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + break; + } + store_reg(s, rd, tmp); + break; + case 6: case 7: /* 64-bit multiply, Divide. */ + op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if ((op & 0x50) == 0x10) { + /* sdiv, udiv */ + if (!arm_feature(env, ARM_FEATURE_DIV)) + goto illegal_op; + if (op & 0x20) + gen_helper_udiv(tmp, tmp, tmp2); + else + gen_helper_sdiv(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else if ((op & 0xe) == 0xc) { + /* Dual multiply accumulate long. */ + if (op & 1) + gen_swap_half(tmp2); + gen_smul_dual(tmp, tmp2); + if (op & 0x10) { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + /* BUGFIX */ + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + gen_addq(s, tmp64, rs, rd); + gen_storeq_reg(s, rs, rd, tmp64); + tcg_temp_free_i64(tmp64); + } else { + if (op & 0x20) { + /* Unsigned 64-bit multiply */ + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + } else { + if (op & 8) { + /* smlalxy */ + gen_mulxy(tmp, tmp2, op & 2, op & 1); + dead_tmp(tmp2); + tmp64 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(tmp64, tmp); + dead_tmp(tmp); + } else { + /* Signed 64-bit multiply */ + tmp64 = gen_muls_i64_i32(tmp, tmp2); + } + } + if (op & 4) { + /* umaal */ + gen_addq_lo(s, tmp64, rs); + gen_addq_lo(s, tmp64, rd); + } else if (op & 0x40) { + /* 64-bit accumulate. */ + gen_addq(s, tmp64, rs, rd); + } + gen_storeq_reg(s, rs, rd, tmp64); + tcg_temp_free_i64(tmp64); + } + break; + } + break; + case 6: case 7: case 14: case 15: + /* Coprocessor. */ + if (((insn >> 24) & 3) == 3) { + /* Translate into the equivalent ARM encoding. */ + insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4); + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + } else { + if (insn & (1 << 28)) + goto illegal_op; + if (disas_coproc_insn (env, s, insn)) + goto illegal_op; + } + break; + case 8: case 9: case 10: case 11: + if (insn & (1 << 15)) { + /* Branches, misc control. */ + if (insn & 0x5000) { + /* Unconditional branch. */ + /* signextend(hw1[10:0]) -> offset[:12]. */ + offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff; + /* hw1[10:0] -> offset[11:1]. */ + offset |= (insn & 0x7ff) << 1; + /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22] + offset[24:22] already have the same value because of the + sign extension above. */ + offset ^= ((~insn) & (1 << 13)) << 10; + offset ^= ((~insn) & (1 << 11)) << 11; + + if (insn & (1 << 14)) { + /* Branch and link. */ + tcg_gen_movi_i32(cpu_R[14], s->pc | 1); + } + + offset += s->pc; + if (insn & (1 << 12)) { + /* b/bl */ + gen_jmp(s, offset); + } else { + /* blx */ + offset &= ~(uint32_t)2; + gen_bx_im(s, offset); + } + } else if (((insn >> 23) & 7) == 7) { + /* Misc control */ + if (insn & (1 << 13)) + goto illegal_op; + + if (insn & (1 << 26)) { + /* Secure monitor call (v6Z) */ + goto illegal_op; /* not implemented. */ + } else { + op = (insn >> 20) & 7; + switch (op) { + case 0: /* msr cpsr. */ + if (IS_M(env)) { + tmp = load_reg(s, rn); + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + dead_tmp(tmp); + gen_lookup_tb(s); + break; + } + /* fall through */ + case 1: /* msr spsr. */ + if (IS_M(env)) + goto illegal_op; + tmp = load_reg(s, rn); + if (gen_set_psr(s, + msr_mask(env, s, (insn >> 8) & 0xf, op == 1), + op == 1, tmp)) + goto illegal_op; + break; + case 2: /* cps, nop-hint. */ + if (((insn >> 8) & 7) == 0) { + gen_nop_hint(s, insn & 0xff); + } + /* Implemented as NOP in user mode. */ + if (IS_USER(s)) + break; + offset = 0; + imm = 0; + if (insn & (1 << 10)) { + if (insn & (1 << 7)) + offset |= CPSR_A; + if (insn & (1 << 6)) + offset |= CPSR_I; + if (insn & (1 << 5)) + offset |= CPSR_F; + if (insn & (1 << 9)) + imm = CPSR_A | CPSR_I | CPSR_F; + } + if (insn & (1 << 8)) { + offset |= 0x1f; + imm |= (insn & 0x1f); + } + if (offset) { + gen_set_psr_im(s, offset, 0, imm); + } + break; + case 3: /* Special control operations. */ + ARCH(7); + op = (insn >> 4) & 0xf; + switch (op) { + case 2: /* clrex */ + gen_clrex(s); + break; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + /* These execute as NOPs. */ + break; + default: + goto illegal_op; + } + break; + case 4: /* bxj */ + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, rn); + gen_bx(s, tmp); + break; + case 5: /* Exception return. */ + /* Unpredictable in user mode. */ + goto illegal_op; + case 6: /* mrs cpsr. */ + tmp = new_tmp(); + if (IS_M(env)) { + addr = tcg_const_i32(insn & 0xff); + gen_helper_v7m_mrs(tmp, cpu_env, addr); + tcg_temp_free_i32(addr); + } else { + gen_helper_cpsr_read(tmp); + } + store_reg(s, rd, tmp); + break; + case 7: /* mrs spsr. */ + /* Not accessible in user mode. */ + if (IS_USER(s) || IS_M(env)) + goto illegal_op; + tmp = load_cpu_field(spsr); + store_reg(s, rd, tmp); + break; + } + } + } else { + /* Conditional branch. */ + op = (insn >> 22) & 0xf; + /* Generate a conditional jump to next instruction. */ + s->condlabel = gen_new_label(); + gen_test_cc(op ^ 1, s->condlabel); + s->condjmp = 1; + + /* offset[11:1] = insn[10:0] */ + offset = (insn & 0x7ff) << 1; + /* offset[17:12] = insn[21:16]. */ + offset |= (insn & 0x003f0000) >> 4; + /* offset[31:20] = insn[26]. */ + offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11; + /* offset[18] = insn[13]. */ + offset |= (insn & (1 << 13)) << 5; + /* offset[19] = insn[11]. */ + offset |= (insn & (1 << 11)) << 8; + + /* jump to the offset */ + gen_jmp(s, s->pc + offset); + } + } else { + /* Data processing immediate. */ + if (insn & (1 << 25)) { + if (insn & (1 << 24)) { + if (insn & (1 << 20)) + goto illegal_op; + /* Bitfield/Saturate. */ + op = (insn >> 21) & 7; + imm = insn & 0x1f; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + switch (op) { + case 2: /* Signed bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_sbfx(tmp, shift, imm); + break; + case 6: /* Unsigned bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_ubfx(tmp, shift, (1u << imm) - 1); + break; + case 3: /* Bitfield insert/clear. */ + if (imm < shift) + goto illegal_op; + imm = imm + 1 - shift; + if (imm != 32) { + tmp2 = load_reg(s, rd); + gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1); + dead_tmp(tmp2); + } + break; + case 7: + goto illegal_op; + default: /* Saturate. */ + if (shift) { + if (op & 1) + tcg_gen_sari_i32(tmp, tmp, shift); + else + tcg_gen_shli_i32(tmp, tmp, shift); + } + tmp2 = tcg_const_i32(imm); + if (op & 4) { + /* Unsigned. */ + if ((op & 1) && shift == 0) + gen_helper_usat16(tmp, tmp, tmp2); + else + gen_helper_usat(tmp, tmp, tmp2); + } else { + /* Signed. */ + if ((op & 1) && shift == 0) + gen_helper_ssat16(tmp, tmp, tmp2); + else + gen_helper_ssat(tmp, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + break; + } + store_reg(s, rd, tmp); + } else { + imm = ((insn & 0x04000000) >> 15) + | ((insn & 0x7000) >> 4) | (insn & 0xff); + if (insn & (1 << 22)) { + /* 16-bit immediate. */ + imm |= (insn >> 4) & 0xf000; + if (insn & (1 << 23)) { + /* movt */ + tmp = load_reg(s, rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, imm << 16); + } else { + /* movw */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, imm); + } + } else { + /* Add/sub 12-bit immediate. */ + if (rn == 15) { + offset = s->pc & ~(uint32_t)3; + if (insn & (1 << 23)) + offset -= imm; + else + offset += imm; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, offset); + } else { + tmp = load_reg(s, rn); + if (insn & (1 << 23)) + tcg_gen_subi_i32(tmp, tmp, imm); + else + tcg_gen_addi_i32(tmp, tmp, imm); + } + } + store_reg(s, rd, tmp); + } + } else { + int shifter_out = 0; + /* modified 12-bit immediate. */ + shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12); + imm = (insn & 0xff); + switch (shift) { + case 0: /* XY */ + /* Nothing to do. */ + break; + case 1: /* 00XY00XY */ + imm |= imm << 16; + break; + case 2: /* XY00XY00 */ + imm |= imm << 16; + imm <<= 8; + break; + case 3: /* XYXYXYXY */ + imm |= imm << 16; + imm |= imm << 8; + break; + default: /* Rotated constant. */ + shift = (shift << 1) | (imm >> 7); + imm |= 0x80; + imm = imm << (32 - shift); + shifter_out = 1; + break; + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, imm); + rn = (insn >> 16) & 0xf; + if (rn == 15) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else { + tmp = load_reg(s, rn); + } + op = (insn >> 21) & 0xf; + if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0, + shifter_out, tmp, tmp2)) + goto illegal_op; + dead_tmp(tmp2); + rd = (insn >> 8) & 0xf; + if (rd != 15) { + store_reg(s, rd, tmp); + } else { + dead_tmp(tmp); + } + } + } + break; + case 12: /* Load/store single data item. */ + { + int postinc = 0; + int writeback = 0; + int user; + if ((insn & 0x01100000) == 0x01000000) { + if (disas_neon_ls_insn(env, s, insn)) + goto illegal_op; + break; + } + user = IS_USER(s); + if (rn == 15) { + addr = new_tmp(); + /* PC relative. */ + /* s->pc has already been incremented by 4. */ + imm = s->pc & 0xfffffffc; + if (insn & (1 << 23)) + imm += insn & 0xfff; + else + imm -= insn & 0xfff; + tcg_gen_movi_i32(addr, imm); + } else { + addr = load_reg(s, rn); + if (insn & (1 << 23)) { + /* Positive offset. */ + imm = insn & 0xfff; + tcg_gen_addi_i32(addr, addr, imm); + } else { + op = (insn >> 8) & 7; + imm = insn & 0xff; + switch (op) { + case 0: case 8: /* Shifted Register. */ + shift = (insn >> 4) & 0xf; + if (shift > 3) + goto illegal_op; + tmp = load_reg(s, rm); + if (shift) + tcg_gen_shli_i32(tmp, tmp, shift); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + break; + case 4: /* Negative offset. */ + tcg_gen_addi_i32(addr, addr, -imm); + break; + case 6: /* User privilege. */ + tcg_gen_addi_i32(addr, addr, imm); + user = 1; + break; + case 1: /* Post-decrement. */ + imm = -imm; + /* Fall through. */ + case 3: /* Post-increment. */ + postinc = 1; + writeback = 1; + break; + case 5: /* Pre-decrement. */ + imm = -imm; + /* Fall through. */ + case 7: /* Pre-increment. */ + tcg_gen_addi_i32(addr, addr, imm); + writeback = 1; + break; + default: + goto illegal_op; + } + } + } + op = ((insn >> 21) & 3) | ((insn >> 22) & 4); + if (insn & (1 << 20)) { + /* Load. */ + if (rs == 15 && op != 2) { + if (op & 2) + goto illegal_op; + /* Memory hint. Implemented as NOP. */ + } else { + switch (op) { + case 0: tmp = gen_ld8u(addr, user); break; + case 4: tmp = gen_ld8s(addr, user); break; + case 1: tmp = gen_ld16u(addr, user); break; + case 5: tmp = gen_ld16s(addr, user); break; + case 2: tmp = gen_ld32(addr, user); break; + default: goto illegal_op; + } + if (rs == 15) { + gen_bx(s, tmp); + } else { + store_reg(s, rs, tmp); + } + } + } else { + /* Store. */ + if (rs == 15) + goto illegal_op; + tmp = load_reg(s, rs); + switch (op) { + case 0: gen_st8(tmp, addr, user); break; + case 1: gen_st16(tmp, addr, user); break; + case 2: gen_st32(tmp, addr, user); break; + default: goto illegal_op; + } + } + if (postinc) + tcg_gen_addi_i32(addr, addr, imm); + if (writeback) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + } + break; + default: + goto illegal_op; + } + return 0; +illegal_op: + return 1; +} + +static void disas_thumb_insn(CPUState *env, DisasContext *s) +{ + uint32_t val, insn, op, rm, rn, rd, shift, cond; + int32_t offset; + int i; + TCGv tmp; + TCGv tmp2; + TCGv addr; + + if (s->condexec_mask) { + cond = s->condexec_cond; + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + } + + insn = lduw_code(s->pc); + s->pc += 2; + + switch (insn >> 12) { + case 0: case 1: + + rd = insn & 7; + op = (insn >> 11) & 3; + if (op == 3) { + /* add/subtract */ + rn = (insn >> 3) & 7; + tmp = load_reg(s, rn); + if (insn & (1 << 10)) { + /* immediate */ + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, (insn >> 6) & 7); + } else { + /* reg */ + rm = (insn >> 6) & 7; + tmp2 = load_reg(s, rm); + } + if (insn & (1 << 9)) { + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp2); + store_reg(s, rd, tmp); + } else { + /* shift immediate */ + rm = (insn >> 3) & 7; + shift = (insn >> 6) & 0x1f; + tmp = load_reg(s, rm); + gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0); + if (!s->condexec_mask) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + } + break; + case 2: case 3: + /* arithmetic large immediate */ + op = (insn >> 11) & 3; + rd = (insn >> 8) & 0x7; + if (op == 0) { /* mov */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, insn & 0xff); + if (!s->condexec_mask) + gen_logic_CC(tmp); + store_reg(s, rd, tmp); + } else { + tmp = load_reg(s, rd); + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, insn & 0xff); + switch (op) { + case 1: /* cmp */ + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp); + dead_tmp(tmp2); + break; + case 2: /* add */ + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else + gen_helper_add_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 3: /* sub */ + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + } + } + break; + case 4: + if (insn & (1 << 11)) { + rd = (insn >> 8) & 7; + /* load pc-relative. Bit 1 of PC is ignored. */ + val = s->pc + 2 + ((insn & 0xff) * 4); + val &= ~(uint32_t)2; + addr = new_tmp(); + tcg_gen_movi_i32(addr, val); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(addr); + store_reg(s, rd, tmp); + break; + } + if (insn & (1 << 10)) { + /* data processing extended or blx */ + rd = (insn & 7) | ((insn >> 4) & 8); + rm = (insn >> 3) & 0xf; + op = (insn >> 8) & 3; + switch (op) { + case 0: /* add */ + tmp = load_reg(s, rd); + tmp2 = load_reg(s, rm); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + store_reg(s, rd, tmp); + break; + case 1: /* cmp */ + tmp = load_reg(s, rd); + tmp2 = load_reg(s, rm); + gen_helper_sub_cc(tmp, tmp, tmp2); + dead_tmp(tmp2); + dead_tmp(tmp); + break; + case 2: /* mov/cpy */ + tmp = load_reg(s, rm); + store_reg(s, rd, tmp); + break; + case 3:/* branch [and link] exchange thumb register */ + tmp = load_reg(s, rm); + if (insn & (1 << 7)) { + val = (uint32_t)s->pc | 1; + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + store_reg(s, 14, tmp2); + } + gen_bx(s, tmp); + break; + } + break; + } + + /* data processing register */ + rd = insn & 7; + rm = (insn >> 3) & 7; + op = (insn >> 6) & 0xf; + if (op == 2 || op == 3 || op == 4 || op == 7) { + /* the shift/rotate ops want the operands backwards */ + val = rm; + rm = rd; + rd = val; + val = 1; + } else { + val = 0; + } + + if (op == 9) { /* neg */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + } else if (op != 0xf) { /* mvn doesn't read its first operand */ + tmp = load_reg(s, rd); + } else { + TCGV_UNUSED(tmp); + } + + tmp2 = load_reg(s, rm); + switch (op) { + case 0x0: /* and */ + tcg_gen_and_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0x1: /* eor */ + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0x2: /* lsl */ + if (s->condexec_mask) { + gen_helper_shl(tmp2, tmp2, tmp); + } else { + gen_helper_shl_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x3: /* lsr */ + if (s->condexec_mask) { + gen_helper_shr(tmp2, tmp2, tmp); + } else { + gen_helper_shr_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x4: /* asr */ + if (s->condexec_mask) { + gen_helper_sar(tmp2, tmp2, tmp); + } else { + gen_helper_sar_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x5: /* adc */ + if (s->condexec_mask) + gen_adc(tmp, tmp2); + else + gen_helper_adc_cc(tmp, tmp, tmp2); + break; + case 0x6: /* sbc */ + if (s->condexec_mask) + gen_sub_carry(tmp, tmp, tmp2); + else + gen_helper_sbc_cc(tmp, tmp, tmp2); + break; + case 0x7: /* ror */ + if (s->condexec_mask) { + tcg_gen_andi_i32(tmp, tmp, 0x1f); + tcg_gen_rotr_i32(tmp2, tmp2, tmp); + } else { + gen_helper_ror_cc(tmp2, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x8: /* tst */ + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + rd = 16; + break; + case 0x9: /* neg */ + if (s->condexec_mask) + tcg_gen_neg_i32(tmp, tmp2); + else + gen_helper_sub_cc(tmp, tmp, tmp2); + break; + case 0xa: /* cmp */ + gen_helper_sub_cc(tmp, tmp, tmp2); + rd = 16; + break; + case 0xb: /* cmn */ + gen_helper_add_cc(tmp, tmp, tmp2); + rd = 16; + break; + case 0xc: /* orr */ + tcg_gen_or_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xd: /* mul */ + tcg_gen_mul_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xe: /* bic */ + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp); + break; + case 0xf: /* mvn */ + tcg_gen_not_i32(tmp2, tmp2); + if (!s->condexec_mask) + gen_logic_CC(tmp2); + val = 1; + rm = rd; + break; + } + if (rd != 16) { + if (val) { + store_reg(s, rm, tmp2); + if (op != 0xf) + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + dead_tmp(tmp2); + } + } else { + dead_tmp(tmp); + dead_tmp(tmp2); + } + break; + + case 5: + /* load/store register offset. */ + rd = insn & 7; + rn = (insn >> 3) & 7; + rm = (insn >> 6) & 7; + op = (insn >> 9) & 7; + addr = load_reg(s, rn); + tmp = load_reg(s, rm); + tcg_gen_add_i32(addr, addr, tmp); + dead_tmp(tmp); + + if (op < 3) /* store */ + tmp = load_reg(s, rd); + + switch (op) { + case 0: /* str */ + gen_st32(tmp, addr, IS_USER(s)); + break; + case 1: /* strh */ + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: /* strb */ + gen_st8(tmp, addr, IS_USER(s)); + break; + case 3: /* ldrsb */ + tmp = gen_ld8s(addr, IS_USER(s)); + break; + case 4: /* ldr */ + tmp = gen_ld32(addr, IS_USER(s)); + break; + case 5: /* ldrh */ + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 6: /* ldrb */ + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 7: /* ldrsh */ + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + if (op >= 3) /* load */ + store_reg(s, rd, tmp); + dead_tmp(addr); + break; + + case 6: + /* load/store word immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 4) & 0x7c; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 7: + /* load/store byte immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 6) & 0x1f; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld8u(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st8(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 8: + /* load/store halfword immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + addr = load_reg(s, rn); + val = (insn >> 5) & 0x3e; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld16u(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st16(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 9: + /* load/store from stack */ + rd = (insn >> 8) & 7; + addr = load_reg(s, 13); + val = (insn & 0xff) * 4; + tcg_gen_addi_i32(addr, addr, val); + + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, rd, tmp); + } else { + /* store */ + tmp = load_reg(s, rd); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + break; + + case 10: + /* add to high reg */ + rd = (insn >> 8) & 7; + if (insn & (1 << 11)) { + /* SP */ + tmp = load_reg(s, 13); + } else { + /* PC. bit 1 is ignored. */ + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2); + } + val = (insn & 0xff) * 4; + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, rd, tmp); + break; + + case 11: + /* misc */ + op = (insn >> 8) & 0xf; + switch (op) { + case 0: + /* adjust stack pointer */ + tmp = load_reg(s, 13); + val = (insn & 0x7f) * 4; + if (insn & (1 << 7)) + val = -(int32_t)val; + tcg_gen_addi_i32(tmp, tmp, val); + store_reg(s, 13, tmp); + break; + + case 2: /* sign/zero extend. */ + ARCH(6); + rd = insn & 7; + rm = (insn >> 3) & 7; + tmp = load_reg(s, rm); + switch ((insn >> 6) & 3) { + case 0: gen_sxth(tmp); break; + case 1: gen_sxtb(tmp); break; + case 2: gen_uxth(tmp); break; + case 3: gen_uxtb(tmp); break; + } + store_reg(s, rd, tmp); + break; + case 4: case 5: case 0xc: case 0xd: + /* push/pop */ + addr = load_reg(s, 13); + if (insn & (1 << 8)) + offset = 4; + else + offset = 0; + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) + offset += 4; + } + if ((insn & (1 << 11)) == 0) { + tcg_gen_addi_i32(addr, addr, -offset); + } + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + if (insn & (1 << 11)) { + /* pop */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); + } else { + /* push */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + /* advance to the next address. */ + tcg_gen_addi_i32(addr, addr, 4); + } + } + TCGV_UNUSED(tmp); + if (insn & (1 << 8)) { + if (insn & (1 << 11)) { + /* pop pc */ + tmp = gen_ld32(addr, IS_USER(s)); + /* don't set the pc until the rest of the instruction + has completed */ + } else { + /* push lr */ + tmp = load_reg(s, 14); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_addi_i32(addr, addr, 4); + } + if ((insn & (1 << 11)) == 0) { + tcg_gen_addi_i32(addr, addr, -offset); + } + /* write back the new stack pointer */ + store_reg(s, 13, addr); + /* set the new PC value */ + if ((insn & 0x0900) == 0x0900) + gen_bx(s, tmp); + break; + + case 1: case 3: case 9: case 11: /* czb */ + rm = insn & 7; + tmp = load_reg(s, rm); + s->condlabel = gen_new_label(); + s->condjmp = 1; + if (insn & (1 << 11)) + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel); + else + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel); + dead_tmp(tmp); + offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; + val = (uint32_t)s->pc + 2; + val += offset; + gen_jmp(s, val); + break; + + case 15: /* IT, nop-hint. */ + if ((insn & 0xf) == 0) { + gen_nop_hint(s, (insn >> 4) & 0xf); + break; + } + /* If Then. */ + s->condexec_cond = (insn >> 4) & 0xe; + s->condexec_mask = insn & 0x1f; + /* No actual code generated for this insn, just setup state. */ + break; + + case 0xe: /* bkpt */ + gen_set_condexec(s); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_BKPT); + s->is_jmp = DISAS_JUMP; + break; + + case 0xa: /* rev */ + ARCH(6); + rn = (insn >> 3) & 0x7; + rd = insn & 0x7; + tmp = load_reg(s, rn); + switch ((insn >> 6) & 3) { + case 0: tcg_gen_bswap32_i32(tmp, tmp); break; + case 1: gen_rev16(tmp); break; + case 3: gen_revsh(tmp); break; + default: goto illegal_op; + } + store_reg(s, rd, tmp); + break; + + case 6: /* cps */ + ARCH(6); + if (IS_USER(s)) + break; + if (IS_M(env)) { + tmp = tcg_const_i32((insn & (1 << 4)) != 0); + /* PRIMASK */ + if (insn & 1) { + addr = tcg_const_i32(16); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + /* FAULTMASK */ + if (insn & 2) { + addr = tcg_const_i32(17); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + tcg_temp_free_i32(tmp); + gen_lookup_tb(s); + } else { + if (insn & (1 << 4)) + shift = CPSR_A | CPSR_I | CPSR_F; + else + shift = 0; + gen_set_psr_im(s, shift, 0, ((insn & 7) << 6) & shift); + } + break; + + default: + goto undef; + } + break; + + case 12: + /* load/store multiple */ + rn = (insn >> 8) & 0x7; + addr = load_reg(s, rn); + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + if (insn & (1 << 11)) { + /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + store_reg(s, i, tmp); + } else { + /* store */ + tmp = load_reg(s, i); + gen_st32(tmp, addr, IS_USER(s)); + } + /* advance to the next address */ + tcg_gen_addi_i32(addr, addr, 4); + } + } + /* Base register writeback. */ + if ((insn & (1 << rn)) == 0) { + store_reg(s, rn, addr); + } else { + dead_tmp(addr); + } + break; + + case 13: + /* conditional branch or swi */ + cond = (insn >> 8) & 0xf; + if (cond == 0xe) + goto undef; + + if (cond == 0xf) { + /* swi */ + gen_set_condexec(s); + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SWI; + break; + } + /* generate a conditional jump to next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(cond ^ 1, s->condlabel); + s->condjmp = 1; + + /* jump to the offset */ + val = (uint32_t)s->pc + 2; + offset = ((int32_t)insn << 24) >> 24; + val += offset << 1; + gen_jmp(s, val); + break; + + case 14: + if (insn & (1 << 11)) { + if (disas_thumb2_insn(env, s, insn)) + goto undef32; + break; + } + /* unconditional branch */ + val = (uint32_t)s->pc; + offset = ((int32_t)insn << 21) >> 21; + val += (offset << 1) + 2; + gen_jmp(s, val); + break; + + case 15: + if (disas_thumb2_insn(env, s, insn)) + goto undef32; + break; + } + return; +undef32: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; + return; +illegal_op: +undef: + gen_set_condexec(s); + gen_set_pc_im(s->pc - 2); + gen_exception(EXCP_UDEF); + s->is_jmp = DISAS_JUMP; +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; + uint16_t *gen_opc_end; + int j, lj; + target_ulong pc_start; + uint32_t next_page_start; + int num_insns; + int max_insns; + + /* generate intermediate code */ + num_temps = 0; + + pc_start = tb->pc; + + dc->tb = tb; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->condjmp = 0; + dc->thumb = env->thumb; + dc->condexec_mask = (env->condexec_bits & 0xf) << 1; + dc->condexec_cond = env->condexec_bits >> 4; +#if !defined(CONFIG_USER_ONLY) + if (IS_M(env)) { + dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1)); + } else { + dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; + } +#endif + cpu_F0s = tcg_temp_new_i32(); + cpu_F1s = tcg_temp_new_i32(); + cpu_F0d = tcg_temp_new_i64(); + cpu_F1d = tcg_temp_new_i64(); + cpu_V0 = cpu_F0d; + cpu_V1 = cpu_F1d; + /* FIXME: cpu_M0 can probably be the same as cpu_V0. */ + cpu_M0 = tcg_temp_new_i64(); + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); + /* Reset the conditional execution bits immediately. This avoids + complications trying to do it at the end of the block. */ + if (env->condexec_bits) + { + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, 0); + store_cpu_field(tmp, condexec_bits); + } + do { +#ifdef CONFIG_USER_ONLY + /* Intercept jump to the magic kernel page. */ + if (dc->pc >= 0xffff0000) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_KERNEL_TRAP); + dc->is_jmp = DISAS_UPDATE; + break; + } +#else + if (dc->pc >= 0xfffffff0 && IS_M(env)) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_EXCEPTION_EXIT); + dc->is_jmp = DISAS_UPDATE; + break; + } +#endif + + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + gen_set_condexec(dc); + gen_set_pc_im(dc->pc); + gen_exception(EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; + goto done_generating; + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + + if (env->thumb) { + disas_thumb_insn(env, dc); + if (dc->condexec_mask) { + dc->condexec_cond = (dc->condexec_cond & 0xe) + | ((dc->condexec_mask >> 4) & 1); + dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f; + if (dc->condexec_mask == 0) { + dc->condexec_cond = 0; + } + } + } else { + disas_arm_insn(env, dc); + } + if (num_temps) { + fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); + num_temps = 0; + } + + if (dc->condjmp && !dc->is_jmp) { + gen_set_label(dc->condlabel); + dc->condjmp = 0; + } + /* Translation stops when a conditional branch is encountered. + * Otherwise the subsequent code could get translated several times. + * Also stop translation when a page boundary is reached. This + * ensures prefetch aborts occur at the right place. */ + num_insns ++; + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && + !singlestep && + dc->pc < next_page_start && + num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + if (dc->condjmp) { + /* FIXME: This can theoretically happen with self-modifying + code. */ + cpu_abort(env, "IO on conditional branch instruction"); + } + gen_io_end(); + } + + /* At this stage dc->condjmp will only be set when the skipped + instruction was a conditional branch or trap, and the PC has + already been written. */ + if (unlikely(env->singlestep_enabled)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (dc->condjmp) { + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI) { + gen_exception(EXCP_SWI); + } else { + gen_exception(EXCP_DEBUG); + } + gen_set_label(dc->condlabel); + } + if (dc->condjmp || !dc->is_jmp) { + gen_set_pc_im(dc->pc); + dc->condjmp = 0; + } + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { + gen_exception(EXCP_SWI); + } else { + /* FIXME: Single stepping a WFI insn will not halt + the CPU. */ + gen_exception(EXCP_DEBUG); + } + } else { + /* While branches must always occur at the end of an IT block, + there are a few other things that can cause us to terminate + the TB in the middel of an IT block: + - Exception generating instructions (bkpt, swi, undefined). + - Page boundaries. + - Hardware watchpoints. + Hardware breakpoints have already been handled and skip this code. + */ + gen_set_condexec(dc); + switch(dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + case DISAS_WFI: + gen_helper_wfi(); + break; + case DISAS_SWI: + gen_exception(EXCP_SWI); + break; + } + if (dc->condjmp) { + gen_set_label(dc->condlabel); + gen_set_condexec(dc); + gen_goto_tb(dc, 1, dc->pc); + dc->condjmp = 0; + } + } + +done_generating: + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("----------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, dc->pc - pc_start, env->thumb); + qemu_log("\n"); + } +#endif + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } +} + +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +static const char *cpu_mode_names[16] = { + "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", + "???", "???", "???", "und", "???", "???", "???", "sys" +}; + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; +#if 0 + union { + uint32_t i; + float s; + } s0, s1; + CPU_DoubleU d; + /* ??? This assumes float64 and double have the same layout. + Oh well, it's only debug dumps. */ + union { + float64 f64; + double d; + } d0; +#endif + uint32_t psr; + + for(i=0;i<16;i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } + psr = cpsr_read(env); + cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + psr & CPSR_T ? 'T' : 'A', + cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); + +#if 0 + for (i = 0; i < 16; i++) { + d.d = env->vfp.regs[i]; + s0.i = d.l.lower; + s1.i = d.l.upper; + d0.f64 = d.d; + cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s, + i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, + d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); +#endif +} + +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->regs[15] = gen_opc_pc[pc_pos]; +} diff --git a/qemu/qemu-git/targphys.h b/qemu/qemu-git/targphys.h new file mode 100644 index 0000000..99ab23c --- /dev/null +++ b/qemu/qemu-git/targphys.h @@ -0,0 +1,24 @@ +/* Define target_phys_addr_t if it exists. */ + +#ifndef TARGPHYS_H +#define TARGPHYS_H + +#ifdef TARGET_PHYS_ADDR_BITS +/* target_phys_addr_t is the type of a physical address (its size can + be different from 'target_ulong'). We have sizeof(target_phys_addr) + = max(sizeof(unsigned long), + sizeof(size_of_target_physical_address)) because we must pass a + host pointer to memory operations in some cases */ + +#if TARGET_PHYS_ADDR_BITS == 32 +typedef uint32_t target_phys_addr_t; +#define TARGET_PHYS_ADDR_MAX UINT32_MAX +#define TARGET_FMT_plx "%08x" +#elif TARGET_PHYS_ADDR_BITS == 64 +typedef uint64_t target_phys_addr_t; +#define TARGET_PHYS_ADDR_MAX UINT64_MAX +#define TARGET_FMT_plx "%016" PRIx64 +#endif +#endif + +#endif diff --git a/qemu/qemu-git/tcg-runtime.c b/qemu/qemu-git/tcg-runtime.c new file mode 100644 index 0000000..219cade --- /dev/null +++ b/qemu/qemu-git/tcg-runtime.c @@ -0,0 +1,61 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "tcg/tcg-runtime.h" + +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2) +{ + return arg1 << arg2; +} + +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2) +{ + return (uint64_t)arg1 >> arg2; +} + +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2) +{ + return arg1 >> arg2; +} + +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2) +{ + return arg1 / arg2; +} + +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2) +{ + return arg1 % arg2; +} + +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 / arg2; +} + +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2) +{ + return arg1 % arg2; +} diff --git a/qemu/qemu-git/tcg/.svn/all-wcprops b/qemu/qemu-git/tcg/.svn/all-wcprops new file mode 100644 index 0000000..630ca68 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/all-wcprops @@ -0,0 +1,53 @@ +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg +END +tcg-op.h +K 25 +svn:wc:ra_dav:version-url +V 52 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/tcg-op.h +END +LICENSE +K 25 +svn:wc:ra_dav:version-url +V 51 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/LICENSE +END +tcg-opc.h +K 25 +svn:wc:ra_dav:version-url +V 53 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/tcg-opc.h +END +tcg.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/tcg.h +END +tcg-runtime.h +K 25 +svn:wc:ra_dav:version-url +V 57 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/tcg-runtime.h +END +TODO +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/TODO +END +README +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/README +END +tcg.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/tcg.c +END diff --git a/qemu/qemu-git/tcg/.svn/entries b/qemu/qemu-git/tcg/.svn/entries new file mode 100644 index 0000000..a14c7b9 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/entries @@ -0,0 +1,327 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-op.h +file + + + + +2013-08-23T00:54:47.000000Z +751d2dc7d578e005034d93bc0801afc9 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +65136 + +arm +dir + +tcg-opc.h +file + + + + +2013-08-23T00:54:47.000000Z +4a07134a8350e09a6eb1085a8e1a8590 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +8525 + +LICENSE +file + + + + +2013-08-23T00:54:47.000000Z +d11ae3b9d7c6d64e64f06995ce28562d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +146 + +ppc +dir + +tcg-runtime.h +file + + + + +2013-08-23T00:54:47.000000Z +0e7974b77cf2837825d42e5b779e02f9 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +473 + +hppa +dir + +i386 +dir + +ppc64 +dir + +README +file + + + + +2013-08-23T00:54:47.000000Z +dd8f60487ad8672620cad0409eca48bc +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +12734 + +tcg.c +file + + + + +2013-08-23T00:54:47.000000Z +b5d3f59022049ce9ae244bcc8b5afca4 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +63169 + +s390 +dir + +x86_64 +dir + +tcg.h +file + + + + +2013-08-23T00:54:47.000000Z +17474dfcc15b2bcef749275db5f8ec97 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +14312 + +TODO +file + + + + +2013-08-23T00:54:47.000000Z +bf07003b0e637aa264b95f358e1da643 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +403 + +mips +dir + +sparc +dir + diff --git a/qemu/qemu-git/tcg/.svn/text-base/LICENSE.svn-base b/qemu/qemu-git/tcg/.svn/text-base/LICENSE.svn-base new file mode 100644 index 0000000..be817fa --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/LICENSE.svn-base @@ -0,0 +1,3 @@ +All the files in this directory and subdirectories are released under +a BSD like license (see header in each file). No other license is +accepted. diff --git a/qemu/qemu-git/tcg/.svn/text-base/README.svn-base b/qemu/qemu-git/tcg/.svn/text-base/README.svn-base new file mode 100644 index 0000000..e672258 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/README.svn-base @@ -0,0 +1,454 @@ +Tiny Code Generator - Fabrice Bellard. + +1) Introduction + +TCG (Tiny Code Generator) began as a generic backend for a C +compiler. It was simplified to be used in QEMU. It also has its roots +in the QOP code generator written by Paul Brook. + +2) Definitions + +The TCG "target" is the architecture for which we generate the +code. It is of course not the same as the "target" of QEMU which is +the emulated architecture. As TCG started as a generic C backend used +for cross compiling, it is assumed that the TCG target is different +from the host, although it is never the case for QEMU. + +A TCG "function" corresponds to a QEMU Translated Block (TB). + +A TCG "temporary" is a variable only live in a basic +block. Temporaries are allocated explicitly in each function. + +A TCG "local temporary" is a variable only live in a function. Local +temporaries are allocated explicitly in each function. + +A TCG "global" is a variable which is live in all the functions +(equivalent of a C global variable). They are defined before the +functions defined. A TCG global can be a memory location (e.g. a QEMU +CPU register), a fixed host register (e.g. the QEMU CPU state pointer) +or a memory location which is stored in a register outside QEMU TBs +(not implemented yet). + +A TCG "basic block" corresponds to a list of instructions terminated +by a branch instruction. + +3) Intermediate representation + +3.1) Introduction + +TCG instructions operate on variables which are temporaries, local +temporaries or globals. TCG instructions and variables are strongly +typed. Two types are supported: 32 bit integers and 64 bit +integers. Pointers are defined as an alias to 32 bit or 64 bit +integers depending on the TCG target word size. + +Each instruction has a fixed number of output variable operands, input +variable operands and always constant operands. + +The notable exception is the call instruction which has a variable +number of outputs and inputs. + +In the textual form, output operands usually come first, followed by +input operands, followed by constant operands. The output type is +included in the instruction name. Constants are prefixed with a '$'. + +add_i32 t0, t1, t2 (t0 <- t1 + t2) + +3.2) Assumptions + +* Basic blocks + +- Basic blocks end after branches (e.g. brcond_i32 instruction), + goto_tb and exit_tb instructions. +- Basic blocks start after the end of a previous basic block, or at a + set_label instruction. + +After the end of a basic block, the content of temporaries is +destroyed, but local temporaries and globals are preserved. + +* Floating point types are not supported yet + +* Pointers: depending on the TCG target, pointer size is 32 bit or 64 + bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or + TCG_TYPE_I64. + +* Helpers: + +Using the tcg_gen_helper_x_y it is possible to call any function +taking i32, i64 or pointer types. Before calling an helper, all +globals are stored at their canonical location and it is assumed that +the function can modify them. In the future, function modifiers will +be allowed to tell that the helper does not read or write some globals. + +On some TCG targets (e.g. x86), several calling conventions are +supported. + +* Branches: + +Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an +explicit address. Conditional branches can only jump to labels. + +3.3) Code Optimizations + +When generating instructions, you can count on at least the following +optimizations: + +- Single instructions are simplified, e.g. + + and_i32 t0, t0, $0xffffffff + + is suppressed. + +- A liveness analysis is done at the basic block level. The + information is used to suppress moves from a dead variable to + another one. It is also used to remove instructions which compute + dead results. The later is especially useful for condition code + optimization in QEMU. + + In the following example: + + add_i32 t0, t1, t2 + add_i32 t0, t0, $1 + mov_i32 t0, $1 + + only the last instruction is kept. + +3.4) Instruction Reference + +********* Function call + +* call ptr + +call function 'ptr' (pointer type) + + optional 32 bit or 64 bit return value + optional 32 bit or 64 bit parameters + +********* Jumps/Labels + +* jmp t0 + +Absolute jump to address t0 (pointer type). + +* set_label $label + +Define label 'label' at the current program point. + +* br $label + +Jump to label. + +* brcond_i32/i64 cond, t0, t1, label + +Conditional jump if t0 cond t1 is true. cond can be: + TCG_COND_EQ + TCG_COND_NE + TCG_COND_LT /* signed */ + TCG_COND_GE /* signed */ + TCG_COND_LE /* signed */ + TCG_COND_GT /* signed */ + TCG_COND_LTU /* unsigned */ + TCG_COND_GEU /* unsigned */ + TCG_COND_LEU /* unsigned */ + TCG_COND_GTU /* unsigned */ + +********* Arithmetic + +* add_i32/i64 t0, t1, t2 + +t0=t1+t2 + +* sub_i32/i64 t0, t1, t2 + +t0=t1-t2 + +* neg_i32/i64 t0, t1 + +t0=-t1 (two's complement) + +* mul_i32/i64 t0, t1, t2 + +t0=t1*t2 + +* div_i32/i64 t0, t1, t2 + +t0=t1/t2 (signed). Undefined behavior if division by zero or overflow. + +* divu_i32/i64 t0, t1, t2 + +t0=t1/t2 (unsigned). Undefined behavior if division by zero. + +* rem_i32/i64 t0, t1, t2 + +t0=t1%t2 (signed). Undefined behavior if division by zero or overflow. + +* remu_i32/i64 t0, t1, t2 + +t0=t1%t2 (unsigned). Undefined behavior if division by zero. + +********* Logical + +* and_i32/i64 t0, t1, t2 + +t0=t1&t2 + +* or_i32/i64 t0, t1, t2 + +t0=t1|t2 + +* xor_i32/i64 t0, t1, t2 + +t0=t1^t2 + +* not_i32/i64 t0, t1 + +t0=~t1 + +* andc_i32/i64 t0, t1, t2 + +t0=t1&~t2 + +* eqv_i32/i64 t0, t1, t2 + +t0=~(t1^t2) + +* nand_i32/i64 t0, t1, t2 + +t0=~(t1&t2) + +* nor_i32/i64 t0, t1, t2 + +t0=~(t1|t2) + +* orc_i32/i64 t0, t1, t2 + +t0=t1|~t2 + +********* Shifts/Rotates + +* shl_i32/i64 t0, t1, t2 + +t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* shr_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* sar_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotl_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotr_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +********* Misc + +* mov_i32/i64 t0, t1 + +t0 = t1 + +Move t1 to t0 (both operands must have the same type). + +* ext8s_i32/i64 t0, t1 +ext8u_i32/i64 t0, t1 +ext16s_i32/i64 t0, t1 +ext16u_i32/i64 t0, t1 +ext32s_i64 t0, t1 +ext32u_i64 t0, t1 + +8, 16 or 32 bit sign/zero extension (both operands must have the same type) + +* bswap16_i32/i64 t0, t1 + +16 bit byte swap on a 32/64 bit value. The two/six high order bytes must be +set to zero. + +* bswap32_i32/i64 t0, t1 + +32 bit byte swap on a 32/64 bit value. With a 64 bit value, the four high +order bytes must be set to zero. + +* bswap64_i64 t0, t1 + +64 bit byte swap + +* discard_i32/i64 t0 + +Indicate that the value of t0 won't be used later. It is useful to +force dead code elimination. + +********* Type conversions + +* ext_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does sign extension + +* extu_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does zero extension + +* trunc_i64_i32 t0, t1 +Truncate t1 (64 bit) to t0 (32 bit) + +* concat_i32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half +from t2 (32 bit). + +* concat32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half +from t2 (64 bit). + +********* Load/Store + +* ld_i32/i64 t0, t1, offset +ld8s_i32/i64 t0, t1, offset +ld8u_i32/i64 t0, t1, offset +ld16s_i32/i64 t0, t1, offset +ld16u_i32/i64 t0, t1, offset +ld32s_i64 t0, t1, offset +ld32u_i64 t0, t1, offset + +t0 = read(t1 + offset) +Load 8, 16, 32 or 64 bits with or without sign extension from host memory. +offset must be a constant. + +* st_i32/i64 t0, t1, offset +st8_i32/i64 t0, t1, offset +st16_i32/i64 t0, t1, offset +st32_i64 t0, t1, offset + +write(t0, t1 + offset) +Write 8, 16, 32 or 64 bits to host memory. + +********* QEMU specific operations + +* tb_exit t0 + +Exit the current TB and return the value t0 (word type). + +* goto_tb index + +Exit the current TB and jump to the TB index 'index' (constant) if the +current TB was linked to this TB. Otherwise execute the next +instructions. + +* qemu_ld8u t0, t1, flags +qemu_ld8s t0, t1, flags +qemu_ld16u t0, t1, flags +qemu_ld16s t0, t1, flags +qemu_ld32u t0, t1, flags +qemu_ld32s t0, t1, flags +qemu_ld64 t0, t1, flags + +Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +* qemu_st8 t0, t1, flags +qemu_st16 t0, t1, flags +qemu_st32 t0, t1, flags +qemu_st64 t0, t1, flags + +Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +Note 1: Some shortcuts are defined when the last operand is known to be +a constant (e.g. addi for add, movi for mov). + +Note 2: When using TCG, the opcodes must never be generated directly +as some of them may not be available as "real" opcodes. Always use the +function tcg_gen_xxx(args). + +4) Backend + +tcg-target.h contains the target specific definitions. tcg-target.c +contains the target specific code. + +4.1) Assumptions + +The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or +64 bit. It is expected that the pointer has the same size as the word. + +On a 32 bit target, all 64 bit operations are converted to 32 bits. A +few specific operations must be implemented to allow it (see add2_i32, +sub2_i32, brcond2_i32). + +Floating point operations are not supported in this version. A +previous incarnation of the code generator had full support of them, +but it is better to concentrate on integer operations first. + +On a 64 bit target, no assumption is made in TCG about the storage of +the 32 bit values in 64 bit registers. + +4.2) Constraints + +GCC like constraints are used to define the constraints of every +instruction. Memory constraints are not supported in this +version. Aliases are specified in the input operands as for GCC. + +The same register may be used for both an input and an output, even when +they are not explicitly aliased. If an op expands to multiple target +instructions then care must be taken to avoid clobbering input values. +GCC style "early clobber" outputs are not currently supported. + +A target can define specific register or constant constraints. If an +operation uses a constant input constraint which does not allow all +constants, it must also accept registers in order to have a fallback. + +The movi_i32 and movi_i64 operations must accept any constants. + +The mov_i32 and mov_i64 operations must accept any registers of the +same type. + +The ld/st instructions must accept signed 32 bit constant offsets. It +can be implemented by reserving a specific register to compute the +address if the offset is too big. + +The ld/st instructions must accept any destination (ld) or source (st) +register. + +4.3) Function call assumptions + +- The only supported types for parameters and return value are: 32 and + 64 bit integers and pointer. +- The stack grows downwards. +- The first N parameters are passed in registers. +- The next parameters are passed on the stack by storing them as words. +- Some registers are clobbered during the call. +- The function can return 0 or 1 value in registers. On a 32 bit + target, functions must be able to return 2 values in registers for + 64 bit return type. + +5) Recommended coding rules for best performance + +- Use globals to represent the parts of the QEMU CPU state which are + often modified, e.g. the integer registers and the condition + codes. TCG will be able to use host registers to store them. + +- Avoid globals stored in fixed registers. They must be used only to + store the pointer to the CPU state and possibly to store a pointer + to a register window. + +- Use temporaries. Use local temporaries only when really needed, + e.g. when you need to use a value after a jump. Local temporaries + introduce a performance hit in the current TCG implementation: their + content is saved to memory at end of each basic block. + +- Free temporaries and local temporaries when they are no longer used + (tcg_temp_free). Since tcg_const_x() also creates a temporary, you + should free it after it is used. Freeing temporaries does not yield + a better generated code, but it reduces the memory usage of TCG and + the speed of the translation. + +- Don't hesitate to use helpers for complicated or seldom used target + intructions. There is little performance advantage in using TCG to + implement target instructions taking more than about twenty TCG + instructions. + +- Use the 'discard' instruction if you know that TCG won't be able to + prove that a given global is "dead" at a given program point. The + x86 target uses it to improve the condition codes optimisation. diff --git a/qemu/qemu-git/tcg/.svn/text-base/TODO.svn-base b/qemu/qemu-git/tcg/.svn/text-base/TODO.svn-base new file mode 100644 index 0000000..f30cb75 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/TODO.svn-base @@ -0,0 +1,14 @@ +- Add new instructions such as: setcond, clz, ctz, popcnt. + +- See if it is worth exporting mul2, mulu2, div2, divu2. + +- Support of globals saved in fixed registers between TBs. + +Ideas: + +- Move the slow part of the qemu_ld/st ops after the end of the TB. + +- Change exception syntax to get closer to QOP system (exception + parameters given with a specific instruction). + +- Add float and vector support. diff --git a/qemu/qemu-git/tcg/.svn/text-base/tcg-op.h.svn-base b/qemu/qemu-git/tcg/.svn/text-base/tcg-op.h.svn-base new file mode 100644 index 0000000..faf2e8b --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/tcg-op.h.svn-base @@ -0,0 +1,2183 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "tcg.h" + +int gen_new_label(void); + +static inline void tcg_gen_op1_i32(int opc, TCGv_i32 arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); +} + +static inline void tcg_gen_op1_i64(int opc, TCGv_i64 arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); +} + +static inline void tcg_gen_op1i(int opc, TCGArg arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; +} + +static inline void tcg_gen_op2_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); +} + +static inline void tcg_gen_op2_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); +} + +static inline void tcg_gen_op2i_i32(int opc, TCGv_i32 arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op2i_i64(int opc, TCGv_i64 arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op2ii(int opc, TCGArg arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op3_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); +} + +static inline void tcg_gen_op3_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); +} + +static inline void tcg_gen_op3i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGArg arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = arg3; +} + +static inline void tcg_gen_op3i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGArg arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = arg3; +} + +static inline void tcg_gen_ldst_op_i32(int opc, TCGv_i32 val, TCGv_ptr base, + TCGArg offset) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(val); + *gen_opparam_ptr++ = GET_TCGV_PTR(base); + *gen_opparam_ptr++ = offset; +} + +static inline void tcg_gen_ldst_op_i64(int opc, TCGv_i64 val, TCGv_ptr base, + TCGArg offset) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_PTR(base); + *gen_opparam_ptr++ = offset; +} + +static inline void tcg_gen_qemu_ldst_op_i64_i32(int opc, TCGv_i64 val, TCGv_i32 addr, + TCGArg mem_index) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_I32(addr); + *gen_opparam_ptr++ = mem_index; +} + +static inline void tcg_gen_qemu_ldst_op_i64_i64(int opc, TCGv_i64 val, TCGv_i64 addr, + TCGArg mem_index) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_I64(addr); + *gen_opparam_ptr++ = mem_index; +} + +static inline void tcg_gen_op4_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); +} + +static inline void tcg_gen_op4_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); +} + +static inline void tcg_gen_op4i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGArg arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = arg3; + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGArg arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = arg3; + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op5_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = GET_TCGV_I32(arg5); +} + +static inline void tcg_gen_op5_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = GET_TCGV_I64(arg5); +} + +static inline void tcg_gen_op5i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = arg5; +} + +static inline void tcg_gen_op5i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = arg5; +} + +static inline void tcg_gen_op6_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5, + TCGv_i32 arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = GET_TCGV_I32(arg5); + *gen_opparam_ptr++ = GET_TCGV_I32(arg6); +} + +static inline void tcg_gen_op6_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5, + TCGv_i64 arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = GET_TCGV_I64(arg5); + *gen_opparam_ptr++ = GET_TCGV_I64(arg6); +} + +static inline void tcg_gen_op6ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5, + TCGArg arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = arg5; + *gen_opparam_ptr++ = arg6; +} + +static inline void tcg_gen_op6ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5, + TCGArg arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = arg5; + *gen_opparam_ptr++ = arg6; +} + +static inline void gen_set_label(int n) +{ + tcg_gen_op1i(INDEX_op_set_label, n); +} + +static inline void tcg_gen_br(int label) +{ + tcg_gen_op1i(INDEX_op_br, label); +} + +static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + if (!TCGV_EQUAL_I32(ret, arg)) + tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg); +} + +static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg) +{ + tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg); +} + +/* helper calls */ +static inline void tcg_gen_helperN(void *func, int flags, int sizemask, + TCGArg ret, int nargs, TCGArg *args) +{ + TCGv_ptr fn; + fn = tcg_const_ptr((tcg_target_long)func); + tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret, + nargs, args); + tcg_temp_free_ptr(fn); +} + +/* FIXME: Should this be pure? */ +static inline void tcg_gen_helper64(void *func, TCGv_i64 ret, + TCGv_i64 a, TCGv_i64 b) +{ + TCGv_ptr fn; + TCGArg args[2]; + fn = tcg_const_ptr((tcg_target_long)func); + args[0] = GET_TCGV_I64(a); + args[1] = GET_TCGV_I64(b); + tcg_gen_callN(&tcg_ctx, fn, 0, 7, GET_TCGV_I64(ret), 2, args); + tcg_temp_free_ptr(fn); +} + +/* 32 bit ops */ + +static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_add_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0 = tcg_const_i32(arg1); + tcg_gen_sub_i32(ret, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_sub_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_movi_i32(ret, 0); + } else if (arg2 == 0xffffffff) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0xffffffff) { + tcg_gen_movi_i32(ret, 0xffffffff); + } else if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_movi_i32(ret, 0); + } else { + tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_xor_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_shl_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_shr_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_sar_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_brcond_i32(int cond, TCGv_i32 arg1, TCGv_i32 arg2, + int label_index) +{ + tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_brcondi_i32(int cond, TCGv_i32 arg1, int32_t arg2, + int label_index) +{ + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_brcond_i32(cond, arg1, t0, label_index); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_mul_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +#ifdef TCG_TARGET_HAS_div_i32 +static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} +#endif + +#if TCG_TARGET_REG_BITS == 32 + +static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + if (!TCGV_EQUAL_I64(ret, arg)) { + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + } +} + +static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) +{ + tcg_gen_movi_i32(TCGV_LOW(ret), arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); +} + +static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), 31); +} + +static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + /* since arg2 and ret have different types, they cannot be the + same temporary */ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); +#else + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); +#else + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +/* XXX: use generic code when basic block handling is OK or CPU + specific code (x86) */ +static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); +} + +static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); +} + +static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, + int label_index) +{ + tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2), cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + TCGv_i32 t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i32(); + + tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0), + TCGV_LOW(arg1), TCGV_LOW(arg2)); + + tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2)); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + + tcg_gen_mov_i64(ret, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i32(t1); +} + +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_remu_i64, ret, arg1, arg2); +} + +#else + +static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + if (!TCGV_EQUAL_I64(ret, arg)) + tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg); +} + +static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) +{ + tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg); +} + +static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_movi_i64(ret, 0); + } else { + tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_xor_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_shl_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_shr_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_sar_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, + int label_index) +{ + tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); +} + +#ifdef TCG_TARGET_HAS_div_i64 +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} +#endif + +#endif + +static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_add_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg1); + tcg_gen_sub_i64(ret, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_sub_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} +static inline void tcg_gen_brcondi_i64(int cond, TCGv_i64 arg1, int64_t arg2, + int label_index) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_brcond_i64(cond, arg1, t0, label_index); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_mul_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + + +/***************************************/ +/* optional operations */ + +static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i32 + tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 24); + tcg_gen_sari_i32(ret, ret, 24); +#endif +} + +static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i32 + tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 16); + tcg_gen_sari_i32(ret, ret, 16); +#endif +} + +static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext8u_i32 + tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); +#else + tcg_gen_andi_i32(ret, arg, 0xffu); +#endif +} + +static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext16u_i32 + tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); +#else + tcg_gen_andi_i32(ret, arg, 0xffffu); +#endif +} + +/* Note: we assume the two high bytes are set to zero */ +static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_bswap16_i32 + tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg); +#else + TCGv_i32 t0 = tcg_temp_new_i32(); + + tcg_gen_ext8u_i32(t0, arg); + tcg_gen_shli_i32(t0, t0, 8); + tcg_gen_shri_i32(ret, arg, 8); + tcg_gen_or_i32(ret, ret, t0); + tcg_temp_free_i32(t0); +#endif +} + +static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_bswap32_i32 + tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg); +#else + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + + tcg_gen_shli_i32(t0, arg, 24); + + tcg_gen_andi_i32(t1, arg, 0x0000ff00); + tcg_gen_shli_i32(t1, t1, 8); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 8); + tcg_gen_andi_i32(t1, t1, 0x0000ff00); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 24); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(ret, TCGV_LOW(arg)); +} + +static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +/* Note: we assume the six high bytes are set to zero */ +static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg)); +} + +/* Note: we assume the four high bytes are set to zero */ +static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg)); +} + +static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + + tcg_gen_bswap32_i32(t0, TCGV_LOW(arg)); + tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg)); + tcg_gen_mov_i32(TCGV_LOW(ret), t1); + tcg_gen_mov_i32(TCGV_HIGH(ret), t0); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +} +#else + +static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i64 + tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 56); + tcg_gen_sari_i64(ret, ret, 56); +#endif +} + +static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i64 + tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 48); + tcg_gen_sari_i64(ret, ret, 48); +#endif +} + +static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext32s_i64 + tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 32); + tcg_gen_sari_i64(ret, ret, 32); +#endif +} + +static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext8u_i64 + tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffu); +#endif +} + +static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext16u_i64 + tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffffu); +#endif +} + +static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext32u_i64 + tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffffffffu); +#endif +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers. This will probably break MIPS64 targets. */ +static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg))); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_ext32u_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg))); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_ext32s_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg))); +} + +/* Note: we assume the six high bytes are set to zero */ +static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap16_i64 + tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ext8u_i64(t0, arg); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(ret, arg, 8); + tcg_gen_or_i64(ret, ret, t0); + tcg_temp_free_i64(t0); +#endif +} + +/* Note: we assume the four high bytes are set to zero */ +static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap32_i64 + tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg); +#else + TCGv_i64 t0, t1; + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_shli_i64(t0, arg, 24); + tcg_gen_ext32u_i64(t0, t0); + + tcg_gen_andi_i64(t1, arg, 0x0000ff00); + tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 8); + tcg_gen_andi_i64(t1, t1, 0x0000ff00); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 24); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap64_i64 + tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_shli_i64(t0, arg, 56); + + tcg_gen_andi_i64(t1, arg, 0x0000ff00); + tcg_gen_shli_i64(t1, t1, 40); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0x00ff0000); + tcg_gen_shli_i64(t1, t1, 24); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0xff000000); + tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 8); + tcg_gen_andi_i64(t1, t1, 0xff000000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 24); + tcg_gen_andi_i64(t1, t1, 0x00ff0000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 40); + tcg_gen_andi_i64(t1, t1, 0x0000ff00); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 56); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +#endif + +static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_neg_i32 + tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg); +#else + TCGv_i32 t0 = tcg_const_i32(0); + tcg_gen_sub_i32(ret, t0, arg); + tcg_temp_free_i32(t0); +#endif +} + +static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_neg_i64 + tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_const_i64(0); + tcg_gen_sub_i64(ret, t0, arg); + tcg_temp_free_i64(t0); +#endif +} + +static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_not_i32 + tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg); +#else + tcg_gen_xori_i32(ret, arg, -1); +#endif +} + +static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_not_i64 + tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); +#else + tcg_gen_xori_i64(ret, arg, -1); +#endif +} + +static inline void tcg_gen_discard_i32(TCGv_i32 arg) +{ + tcg_gen_op1_i32(INDEX_op_discard, arg); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_discard_i64(TCGv_i64 arg) +{ + tcg_gen_discard_i32(TCGV_LOW(arg)); + tcg_gen_discard_i32(TCGV_HIGH(arg)); +} +#else +static inline void tcg_gen_discard_i64(TCGv_i64 arg) +{ + tcg_gen_op1_i64(INDEX_op_discard, arg); +} +#endif + +static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_mov_i32(TCGV_LOW(dest), low); + tcg_gen_mov_i32(TCGV_HIGH(dest), high); +#else + TCGv_i64 tmp = tcg_temp_new_i64(); + /* This extension is only needed for type correctness. + We may be able to do better given target specific information. */ + tcg_gen_extu_i32_i64(tmp, high); + tcg_gen_shli_i64(tmp, tmp, 32); + tcg_gen_extu_i32_i64(dest, low); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free_i64(tmp); +#endif +} + +static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_concat_i32_i64(dest, TCGV_LOW(low), TCGV_LOW(high)); +#else + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(dest, low); + tcg_gen_shli_i64(tmp, high, 32); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free_i64(tmp); +#endif +} + +static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_not_i32(t0, arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_xor_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_xor_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_and_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_and_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_or_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_or_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_not_i32(t0, arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i32 + tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); +#else + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shl_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shr_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i64 + tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); +#else + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shl_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shr_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { +#ifdef TCG_TARGET_HAS_rot_i32 + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_rotl_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +#else + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shli_i32(t0, arg1, arg2); + tcg_gen_shri_i32(t1, arg1, 32 - arg2); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif + } +} + +static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { +#ifdef TCG_TARGET_HAS_rot_i64 + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_rotl_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +#else + TCGv_i64 t0, t1; + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t0, arg1, arg2); + tcg_gen_shri_i64(t1, arg1, 64 - arg2); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif + } +} + +static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i32 + tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); +#else + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shr_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shl_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i64 + tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); +#else + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shr_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shl_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_rotli_i32(ret, arg1, 32 - arg2); + } +} + +static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_rotli_i64(ret, arg1, 64 - arg2); + } +} + +/***************************************/ +/* QEMU specific operations. Their type depend on the QEMU CPU + type. */ +#ifndef TARGET_LONG_BITS +#error must include QEMU headers +#endif + +#if TARGET_LONG_BITS == 32 +#define TCGv TCGv_i32 +#define tcg_temp_new() tcg_temp_new_i32() +#define tcg_global_reg_new tcg_global_reg_new_i32 +#define tcg_global_mem_new tcg_global_mem_new_i32 +#define tcg_temp_local_new() tcg_temp_local_new_i32() +#define tcg_temp_free tcg_temp_free_i32 +#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32 +#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32 +#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x) +#define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b) +#else +#define TCGv TCGv_i64 +#define tcg_temp_new() tcg_temp_new_i64() +#define tcg_global_reg_new tcg_global_reg_new_i64 +#define tcg_global_mem_new tcg_global_mem_new_i64 +#define tcg_temp_local_new() tcg_temp_local_new_i64() +#define tcg_temp_free tcg_temp_free_i64 +#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64 +#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64 +#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x) +#define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b) +#endif + +/* debug info: write the PC of the corresponding QEMU CPU instruction */ +static inline void tcg_gen_debug_insn_start(uint64_t pc) +{ + /* XXX: must really use a 32 bit size for TCGArg in all cases */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + tcg_gen_op2ii(INDEX_op_debug_insn_start, + (uint32_t)(pc), (uint32_t)(pc >> 32)); +#else + tcg_gen_op1i(INDEX_op_debug_insn_start, pc); +#endif +} + +static inline void tcg_gen_exit_tb(tcg_target_long val) +{ + tcg_gen_op1i(INDEX_op_exit_tb, val); +} + +static inline void tcg_gen_goto_tb(int idx) +{ + tcg_gen_op1i(INDEX_op_goto_tb, idx); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld8u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld8u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld8s, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld8s, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld16u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld16u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld16s, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld16s, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), addr, mem_index); +#else + tcg_gen_op5i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(addr), TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st8, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st8, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st16, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st16, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st32, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st32, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), addr, + mem_index); +#else + tcg_gen_op5i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), + TCGV_LOW(addr), TCGV_HIGH(addr), mem_index); +#endif +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i32 +#define tcg_gen_discard_ptr tcg_gen_discard_i32 + +#else /* TCG_TARGET_REG_BITS == 32 */ + +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_ld64, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st8, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st16, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st32, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index); +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i64 +#define tcg_gen_discard_ptr tcg_gen_discard_i64 + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#if TARGET_LONG_BITS == 64 +#define TCG_TYPE_TL TCG_TYPE_I64 +#define tcg_gen_movi_tl tcg_gen_movi_i64 +#define tcg_gen_mov_tl tcg_gen_mov_i64 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i64 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i64 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i64 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i64 +#define tcg_gen_ld32u_tl tcg_gen_ld32u_i64 +#define tcg_gen_ld32s_tl tcg_gen_ld32s_i64 +#define tcg_gen_ld_tl tcg_gen_ld_i64 +#define tcg_gen_st8_tl tcg_gen_st8_i64 +#define tcg_gen_st16_tl tcg_gen_st16_i64 +#define tcg_gen_st32_tl tcg_gen_st32_i64 +#define tcg_gen_st_tl tcg_gen_st_i64 +#define tcg_gen_add_tl tcg_gen_add_i64 +#define tcg_gen_addi_tl tcg_gen_addi_i64 +#define tcg_gen_sub_tl tcg_gen_sub_i64 +#define tcg_gen_neg_tl tcg_gen_neg_i64 +#define tcg_gen_subfi_tl tcg_gen_subfi_i64 +#define tcg_gen_subi_tl tcg_gen_subi_i64 +#define tcg_gen_and_tl tcg_gen_and_i64 +#define tcg_gen_andi_tl tcg_gen_andi_i64 +#define tcg_gen_or_tl tcg_gen_or_i64 +#define tcg_gen_ori_tl tcg_gen_ori_i64 +#define tcg_gen_xor_tl tcg_gen_xor_i64 +#define tcg_gen_xori_tl tcg_gen_xori_i64 +#define tcg_gen_not_tl tcg_gen_not_i64 +#define tcg_gen_shl_tl tcg_gen_shl_i64 +#define tcg_gen_shli_tl tcg_gen_shli_i64 +#define tcg_gen_shr_tl tcg_gen_shr_i64 +#define tcg_gen_shri_tl tcg_gen_shri_i64 +#define tcg_gen_sar_tl tcg_gen_sar_i64 +#define tcg_gen_sari_tl tcg_gen_sari_i64 +#define tcg_gen_brcond_tl tcg_gen_brcond_i64 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i64 +#define tcg_gen_mul_tl tcg_gen_mul_i64 +#define tcg_gen_muli_tl tcg_gen_muli_i64 +#define tcg_gen_div_tl tcg_gen_div_i64 +#define tcg_gen_rem_tl tcg_gen_rem_i64 +#define tcg_gen_divu_tl tcg_gen_divu_i64 +#define tcg_gen_remu_tl tcg_gen_remu_i64 +#define tcg_gen_discard_tl tcg_gen_discard_i64 +#define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_mov_i64 +#define tcg_gen_extu_i32_tl tcg_gen_extu_i32_i64 +#define tcg_gen_ext_i32_tl tcg_gen_ext_i32_i64 +#define tcg_gen_extu_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i64 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i64 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i64 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i64 +#define tcg_gen_ext32u_tl tcg_gen_ext32u_i64 +#define tcg_gen_ext32s_tl tcg_gen_ext32s_i64 +#define tcg_gen_bswap16_tl tcg_gen_bswap16_i64 +#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64 +#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64 +#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i64 +#define tcg_gen_eqv_tl tcg_gen_eqv_i64 +#define tcg_gen_nand_tl tcg_gen_nand_i64 +#define tcg_gen_nor_tl tcg_gen_nor_i64 +#define tcg_gen_orc_tl tcg_gen_orc_i64 +#define tcg_gen_rotl_tl tcg_gen_rotl_i64 +#define tcg_gen_rotli_tl tcg_gen_rotli_i64 +#define tcg_gen_rotr_tl tcg_gen_rotr_i64 +#define tcg_gen_rotri_tl tcg_gen_rotri_i64 +#define tcg_const_tl tcg_const_i64 +#define tcg_const_local_tl tcg_const_local_i64 +#else +#define TCG_TYPE_TL TCG_TYPE_I32 +#define tcg_gen_movi_tl tcg_gen_movi_i32 +#define tcg_gen_mov_tl tcg_gen_mov_i32 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i32 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i32 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i32 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i32 +#define tcg_gen_ld32u_tl tcg_gen_ld_i32 +#define tcg_gen_ld32s_tl tcg_gen_ld_i32 +#define tcg_gen_ld_tl tcg_gen_ld_i32 +#define tcg_gen_st8_tl tcg_gen_st8_i32 +#define tcg_gen_st16_tl tcg_gen_st16_i32 +#define tcg_gen_st32_tl tcg_gen_st_i32 +#define tcg_gen_st_tl tcg_gen_st_i32 +#define tcg_gen_add_tl tcg_gen_add_i32 +#define tcg_gen_addi_tl tcg_gen_addi_i32 +#define tcg_gen_sub_tl tcg_gen_sub_i32 +#define tcg_gen_neg_tl tcg_gen_neg_i32 +#define tcg_gen_subfi_tl tcg_gen_subfi_i32 +#define tcg_gen_subi_tl tcg_gen_subi_i32 +#define tcg_gen_and_tl tcg_gen_and_i32 +#define tcg_gen_andi_tl tcg_gen_andi_i32 +#define tcg_gen_or_tl tcg_gen_or_i32 +#define tcg_gen_ori_tl tcg_gen_ori_i32 +#define tcg_gen_xor_tl tcg_gen_xor_i32 +#define tcg_gen_xori_tl tcg_gen_xori_i32 +#define tcg_gen_not_tl tcg_gen_not_i32 +#define tcg_gen_shl_tl tcg_gen_shl_i32 +#define tcg_gen_shli_tl tcg_gen_shli_i32 +#define tcg_gen_shr_tl tcg_gen_shr_i32 +#define tcg_gen_shri_tl tcg_gen_shri_i32 +#define tcg_gen_sar_tl tcg_gen_sar_i32 +#define tcg_gen_sari_tl tcg_gen_sari_i32 +#define tcg_gen_brcond_tl tcg_gen_brcond_i32 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i32 +#define tcg_gen_mul_tl tcg_gen_mul_i32 +#define tcg_gen_muli_tl tcg_gen_muli_i32 +#define tcg_gen_div_tl tcg_gen_div_i32 +#define tcg_gen_rem_tl tcg_gen_rem_i32 +#define tcg_gen_divu_tl tcg_gen_divu_i32 +#define tcg_gen_remu_tl tcg_gen_remu_i32 +#define tcg_gen_discard_tl tcg_gen_discard_i32 +#define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32 +#define tcg_gen_extu_i32_tl tcg_gen_mov_i32 +#define tcg_gen_ext_i32_tl tcg_gen_mov_i32 +#define tcg_gen_extu_tl_i64 tcg_gen_extu_i32_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i32 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i32 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i32 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i32 +#define tcg_gen_ext32u_tl tcg_gen_mov_i32 +#define tcg_gen_ext32s_tl tcg_gen_mov_i32 +#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32 +#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32 +#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i32 +#define tcg_gen_eqv_tl tcg_gen_eqv_i32 +#define tcg_gen_nand_tl tcg_gen_nand_i32 +#define tcg_gen_nor_tl tcg_gen_nor_i32 +#define tcg_gen_orc_tl tcg_gen_orc_i32 +#define tcg_gen_rotl_tl tcg_gen_rotl_i32 +#define tcg_gen_rotli_tl tcg_gen_rotli_i32 +#define tcg_gen_rotr_tl tcg_gen_rotr_i32 +#define tcg_gen_rotri_tl tcg_gen_rotri_i32 +#define tcg_const_tl tcg_const_i32 +#define tcg_const_local_tl tcg_const_local_i32 +#endif + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_gen_add_ptr tcg_gen_add_i32 +#define tcg_gen_addi_ptr tcg_gen_addi_i32 +#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32 +#else /* TCG_TARGET_REG_BITS == 32 */ +#define tcg_gen_add_ptr tcg_gen_add_i64 +#define tcg_gen_addi_ptr tcg_gen_addi_i64 +#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64 +#endif /* TCG_TARGET_REG_BITS != 32 */ diff --git a/qemu/qemu-git/tcg/.svn/text-base/tcg-opc.h.svn-base b/qemu/qemu-git/tcg/.svn/text-base/tcg-opc.h.svn-base new file mode 100644 index 0000000..b7f3fd7 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/tcg-opc.h.svn-base @@ -0,0 +1,272 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef DEF2 +#define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0) +#endif + +/* predefined ops */ +DEF2(end, 0, 0, 0, 0) /* must be kept first */ +DEF2(nop, 0, 0, 0, 0) +DEF2(nop1, 0, 0, 1, 0) +DEF2(nop2, 0, 0, 2, 0) +DEF2(nop3, 0, 0, 3, 0) +DEF2(nopn, 0, 0, 1, 0) /* variable number of parameters */ + +DEF2(discard, 1, 0, 0, 0) + +DEF2(set_label, 0, 0, 1, 0) +DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ +DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + +DEF2(mov_i32, 1, 1, 0, 0) +DEF2(movi_i32, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i32, 1, 1, 1, 0) +DEF2(ld8s_i32, 1, 1, 1, 0) +DEF2(ld16u_i32, 1, 1, 1, 0) +DEF2(ld16s_i32, 1, 1, 1, 0) +DEF2(ld_i32, 1, 1, 1, 0) +DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i32, 1, 2, 0, 0) +DEF2(sub_i32, 1, 2, 0, 0) +DEF2(mul_i32, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i32 +DEF2(div_i32, 1, 2, 0, 0) +DEF2(divu_i32, 1, 2, 0, 0) +DEF2(rem_i32, 1, 2, 0, 0) +DEF2(remu_i32, 1, 2, 0, 0) +#else +DEF2(div2_i32, 2, 3, 0, 0) +DEF2(divu2_i32, 2, 3, 0, 0) +#endif +DEF2(and_i32, 1, 2, 0, 0) +DEF2(or_i32, 1, 2, 0, 0) +DEF2(xor_i32, 1, 2, 0, 0) +/* shifts/rotates */ +DEF2(shl_i32, 1, 2, 0, 0) +DEF2(shr_i32, 1, 2, 0, 0) +DEF2(sar_i32, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_rot_i32 +DEF2(rotl_i32, 1, 2, 0, 0) +DEF2(rotr_i32, 1, 2, 0, 0) +#endif + +DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#if TCG_TARGET_REG_BITS == 32 +DEF2(add2_i32, 2, 4, 0, 0) +DEF2(sub2_i32, 2, 4, 0, 0) +DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(mulu2_i32, 2, 2, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8s_i32 +DEF2(ext8s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i32 +DEF2(ext16s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8u_i32 +DEF2(ext8u_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16u_i32 +DEF2(ext16u_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap16_i32 +DEF2(bswap16_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap32_i32 +DEF2(bswap32_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_not_i32 +DEF2(not_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_neg_i32 +DEF2(neg_i32, 1, 1, 0, 0) +#endif + +#if TCG_TARGET_REG_BITS == 64 +DEF2(mov_i64, 1, 1, 0, 0) +DEF2(movi_i64, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i64, 1, 1, 1, 0) +DEF2(ld8s_i64, 1, 1, 1, 0) +DEF2(ld16u_i64, 1, 1, 1, 0) +DEF2(ld16s_i64, 1, 1, 1, 0) +DEF2(ld32u_i64, 1, 1, 1, 0) +DEF2(ld32s_i64, 1, 1, 1, 0) +DEF2(ld_i64, 1, 1, 1, 0) +DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i64, 1, 2, 0, 0) +DEF2(sub_i64, 1, 2, 0, 0) +DEF2(mul_i64, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i64 +DEF2(div_i64, 1, 2, 0, 0) +DEF2(divu_i64, 1, 2, 0, 0) +DEF2(rem_i64, 1, 2, 0, 0) +DEF2(remu_i64, 1, 2, 0, 0) +#else +DEF2(div2_i64, 2, 3, 0, 0) +DEF2(divu2_i64, 2, 3, 0, 0) +#endif +DEF2(and_i64, 1, 2, 0, 0) +DEF2(or_i64, 1, 2, 0, 0) +DEF2(xor_i64, 1, 2, 0, 0) +/* shifts/rotates */ +DEF2(shl_i64, 1, 2, 0, 0) +DEF2(shr_i64, 1, 2, 0, 0) +DEF2(sar_i64, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_rot_i64 +DEF2(rotl_i64, 1, 2, 0, 0) +DEF2(rotr_i64, 1, 2, 0, 0) +#endif + +DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#ifdef TCG_TARGET_HAS_ext8s_i64 +DEF2(ext8s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i64 +DEF2(ext16s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext32s_i64 +DEF2(ext32s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8u_i64 +DEF2(ext8u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16u_i64 +DEF2(ext16u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext32u_i64 +DEF2(ext32u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap16_i64 +DEF2(bswap16_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap32_i64 +DEF2(bswap32_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap64_i64 +DEF2(bswap64_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_not_i64 +DEF2(not_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_neg_i64 +DEF2(neg_i64, 1, 1, 0, 0) +#endif +#endif + +/* QEMU specific */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS +DEF2(debug_insn_start, 0, 0, 2, 0) +#else +DEF2(debug_insn_start, 0, 0, 1, 0) +#endif +DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op + constants must be defined */ +#if TCG_TARGET_REG_BITS == 32 +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#else /* TCG_TARGET_REG_BITS == 32 */ + +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#undef DEF2 diff --git a/qemu/qemu-git/tcg/.svn/text-base/tcg-runtime.h.svn-base b/qemu/qemu-git/tcg/.svn/text-base/tcg-runtime.h.svn-base new file mode 100644 index 0000000..e750cc1 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/tcg-runtime.h.svn-base @@ -0,0 +1,13 @@ +#ifndef TCG_RUNTIME_H +#define TCG_RUNTIME_H + +/* tcg-runtime.c */ +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); + +#endif diff --git a/qemu/qemu-git/tcg/.svn/text-base/tcg.c.svn-base b/qemu/qemu-git/tcg/.svn/text-base/tcg.c.svn-base new file mode 100644 index 0000000..3c0e296 --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/tcg.c.svn-base @@ -0,0 +1,2085 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* define it to use liveness analysis (better code) */ +#define USE_LIVENESS_ANALYSIS + +#include "config.h" + +#ifndef CONFIG_DEBUG_TCG +/* define it to suppress various consistency checks (faster) */ +#define NDEBUG +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif +#ifdef _AIX +#include +#endif + +#include "qemu-common.h" +#include "cache-utils.h" +#include "host-utils.h" + +/* Note: the long term plan is to reduce the dependancies on the QEMU + CPU definitions. Currently they are used for qemu_ld/st + instructions */ +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec-all.h" + +#include "tcg-op.h" +#include "elf.h" + +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) +#error GUEST_BASE not supported on this host. +#endif + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend); + +static TCGOpDef tcg_op_defs[] = { +#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size }, +#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 }, +#include "tcg-opc.h" +#undef DEF +#undef DEF2 +}; + +static TCGRegSet tcg_target_available_regs[2]; +static TCGRegSet tcg_target_call_clobber_regs; + +/* XXX: move that inside the context */ +uint16_t *gen_opc_ptr; +TCGArg *gen_opparam_ptr; + +static inline void tcg_out8(TCGContext *s, uint8_t v) +{ + *s->code_ptr++ = v; +} + +static inline void tcg_out16(TCGContext *s, uint16_t v) +{ + *(uint16_t *)s->code_ptr = v; + s->code_ptr += 2; +} + +static inline void tcg_out32(TCGContext *s, uint32_t v) +{ + *(uint32_t *)s->code_ptr = v; + s->code_ptr += 4; +} + +/* label relocation processing */ + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) { + /* FIXME: This may break relocations on RISC targets that + modify instruction fields in place. The caller may not have + written the initial value. */ + patch_reloc(code_ptr, type, l->u.value, addend); + } else { + /* add a new relocation entry */ + r = tcg_malloc(sizeof(TCGRelocation)); + r->type = type; + r->ptr = code_ptr; + r->addend = addend; + r->next = l->u.first_reloc; + l->u.first_reloc = r; + } +} + +static void tcg_out_label(TCGContext *s, int label_index, + tcg_target_long value) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) + tcg_abort(); + r = l->u.first_reloc; + while (r != NULL) { + patch_reloc(r->ptr, r->type, value, r->addend); + r = r->next; + } + l->has_value = 1; + l->u.value = value; +} + +int gen_new_label(void) +{ + TCGContext *s = &tcg_ctx; + int idx; + TCGLabel *l; + + if (s->nb_labels >= TCG_MAX_LABELS) + tcg_abort(); + idx = s->nb_labels++; + l = &s->labels[idx]; + l->has_value = 0; + l->u.first_reloc = NULL; + return idx; +} + +#include "tcg-target.c" + +/* pool based memory allocation */ +void *tcg_malloc_internal(TCGContext *s, int size) +{ + TCGPool *p; + int pool_size; + + if (size > TCG_POOL_CHUNK_SIZE) { + /* big malloc: insert a new pool (XXX: could optimize) */ + p = qemu_malloc(sizeof(TCGPool) + size); + p->size = size; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + p->next = s->pool_current; + } else { + p = s->pool_current; + if (!p) { + p = s->pool_first; + if (!p) + goto new_pool; + } else { + if (!p->next) { + new_pool: + pool_size = TCG_POOL_CHUNK_SIZE; + p = qemu_malloc(sizeof(TCGPool) + pool_size); + p->size = pool_size; + p->next = NULL; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + } else { + p = p->next; + } + } + } + s->pool_current = p; + s->pool_cur = p->data + size; + s->pool_end = p->data + p->size; + return p->data; +} + +void tcg_pool_reset(TCGContext *s) +{ + s->pool_cur = s->pool_end = NULL; + s->pool_current = NULL; +} + +void tcg_context_init(TCGContext *s) +{ + int op, total_args, n; + TCGOpDef *def; + TCGArgConstraint *args_ct; + int *sorted_args; + + memset(s, 0, sizeof(*s)); + s->temps = s->static_temps; + s->nb_globals = 0; + + /* Count total number of arguments and allocate the corresponding + space */ + total_args = 0; + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + n = def->nb_iargs + def->nb_oargs; + total_args += n; + } + + args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args); + sorted_args = qemu_malloc(sizeof(int) * total_args); + + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + def->args_ct = args_ct; + def->sorted_args = sorted_args; + n = def->nb_iargs + def->nb_oargs; + sorted_args += n; + args_ct += n; + } + + tcg_target_init(s); + + /* init global prologue and epilogue */ + s->code_buf = code_gen_prologue; + s->code_ptr = s->code_buf; + tcg_target_qemu_prologue(s); + flush_icache_range((unsigned long)s->code_buf, + (unsigned long)s->code_ptr); +} + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size) +{ + s->frame_start = start; + s->frame_end = start + size; + s->frame_reg = reg; +} + +void tcg_func_start(TCGContext *s) +{ + int i; + tcg_pool_reset(s); + s->nb_temps = s->nb_globals; + for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) + s->first_free_temp[i] = -1; + s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); + s->nb_labels = 0; + s->current_frame_offset = s->frame_start; + + gen_opc_ptr = gen_opc_buf; + gen_opparam_ptr = gen_opparam_buf; +} + +static inline void tcg_temp_alloc(TCGContext *s, int n) +{ + if (n > TCG_MAX_TEMPS) + tcg_abort(); +} + +static inline int tcg_global_reg_new_internal(TCGType type, int reg, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + +#if TCG_TARGET_REG_BITS == 32 + if (type != TCG_TYPE_I32) + tcg_abort(); +#endif + if (tcg_regset_test_reg(s->reserved_regs, reg)) + tcg_abort(); + idx = s->nb_globals; + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 1; + ts->reg = reg; + ts->name = name; + s->nb_globals++; + tcg_regset_set_reg(s->reserved_regs, reg); + return idx; +} + +TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name) +{ + int idx; + + idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name) +{ + int idx; + + idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name); + return MAKE_TCGV_I64(idx); +} + +static inline int tcg_global_mem_new_internal(TCGType type, int reg, + tcg_target_long offset, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + + idx = s->nb_globals; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + char buf[64]; + tcg_temp_alloc(s, s->nb_globals + 2); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset + 4; +#else + ts->mem_offset = offset; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_0"); + ts->name = strdup(buf); + ts++; + + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset; +#else + ts->mem_offset = offset + 4; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_1"); + ts->name = strdup(buf); + + s->nb_globals += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; + ts->mem_offset = offset; + ts->name = name; + s->nb_globals++; + } + return idx; +} + +TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name); + return MAKE_TCGV_I64(idx); +} + +static inline int tcg_temp_new_internal(TCGType type, int temp_local) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx, k; + + k = type; + if (temp_local) + k += TCG_TYPE_COUNT; + idx = s->first_free_temp[k]; + if (idx != -1) { + /* There is already an available temp with the + right type */ + ts = &s->temps[idx]; + s->first_free_temp[k] = ts->next_free_temp; + ts->temp_allocated = 1; + assert(ts->temp_local == temp_local); + } else { + idx = s->nb_temps; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + tcg_temp_alloc(s, s->nb_temps + 2); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + ts++; + ts->base_type = TCG_TYPE_I32; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_temps + 1); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = type; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps++; + } + } + return idx; +} + +TCGv_i32 tcg_temp_new_internal_i32(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_temp_new_internal_i64(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); + return MAKE_TCGV_I64(idx); +} + +static inline void tcg_temp_free_internal(int idx) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int k; + + assert(idx >= s->nb_globals && idx < s->nb_temps); + ts = &s->temps[idx]; + assert(ts->temp_allocated != 0); + ts->temp_allocated = 0; + k = ts->base_type; + if (ts->temp_local) + k += TCG_TYPE_COUNT; + ts->next_free_temp = s->first_free_temp[k]; + s->first_free_temp[k] = idx; +} + +void tcg_temp_free_i32(TCGv_i32 arg) +{ + tcg_temp_free_internal(GET_TCGV_I32(arg)); +} + +void tcg_temp_free_i64(TCGv_i64 arg) +{ + tcg_temp_free_internal(GET_TCGV_I64(arg)); +} + +TCGv_i32 tcg_const_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv_i64 tcg_const_i64(int64_t val) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, val); + return t0; +} + +TCGv_i32 tcg_const_local_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_local_new_i32(); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv_i64 tcg_const_local_i64(int64_t val) +{ + TCGv_i64 t0; + t0 = tcg_temp_local_new_i64(); + tcg_gen_movi_i64(t0, val); + return t0; +} + +void tcg_register_helper(void *func, const char *name) +{ + TCGContext *s = &tcg_ctx; + int n; + if ((s->nb_helpers + 1) > s->allocated_helpers) { + n = s->allocated_helpers; + if (n == 0) { + n = 4; + } else { + n *= 2; + } + s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); + s->allocated_helpers = n; + } + s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; + s->helpers[s->nb_helpers].name = name; + s->nb_helpers++; +} + +/* Note: we convert the 64 bit args to 32 bit and do some alignment + and endian swap. Maybe it would be better to do the alignment + and endian swap in tcg_reg_alloc_call(). */ +void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, + int sizemask, TCGArg ret, int nargs, TCGArg *args) +{ + int call_type; + int i; + int real_args; + int nb_rets; + TCGArg *nparam; + *gen_opc_ptr++ = INDEX_op_call; + nparam = gen_opparam_ptr++; + call_type = (flags & TCG_CALL_TYPE_MASK); + if (ret != TCG_CALL_DUMMY_ARG) { +#if TCG_TARGET_REG_BITS < 64 + if (sizemask & 1) { +#ifdef TCG_TARGET_WORDS_BIGENDIAN + *gen_opparam_ptr++ = ret + 1; + *gen_opparam_ptr++ = ret; +#else + *gen_opparam_ptr++ = ret; + *gen_opparam_ptr++ = ret + 1; +#endif + nb_rets = 2; + } else +#endif + { + *gen_opparam_ptr++ = ret; + nb_rets = 1; + } + } else { + nb_rets = 0; + } + real_args = 0; + for (i = 0; i < nargs; i++) { +#if TCG_TARGET_REG_BITS < 64 + if (sizemask & (2 << i)) { +#ifdef TCG_TARGET_I386 + /* REGPARM case: if the third parameter is 64 bit, it is + allocated on the stack */ + if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { + call_type = TCG_CALL_TYPE_REGPARM_2; + flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; + } +#endif +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + /* some targets want aligned 64 bit args */ + if (real_args & 1) { + *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; + real_args++; + } +#endif +#ifdef TCG_TARGET_WORDS_BIGENDIAN + *gen_opparam_ptr++ = args[i] + 1; + *gen_opparam_ptr++ = args[i]; +#else + *gen_opparam_ptr++ = args[i]; + *gen_opparam_ptr++ = args[i] + 1; +#endif + real_args += 2; + } else +#endif + { + *gen_opparam_ptr++ = args[i]; + real_args++; + } + } + *gen_opparam_ptr++ = GET_TCGV_PTR(func); + + *gen_opparam_ptr++ = flags; + + *nparam = (nb_rets << 16) | (real_args + 1); + + /* total parameters, needed to go backward in the instruction stream */ + *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; +} + +#if TCG_TARGET_REG_BITS == 32 +void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, + int c, int right, int arith) +{ + if (c == 0) { + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); + } else if (c >= 32) { + c -= 32; + if (right) { + if (arith) { + tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); + } else { + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + } + } else { + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); + tcg_gen_movi_i32(TCGV_LOW(ret), 0); + } + } else { + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + if (right) { + tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); + if (arith) + tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); + else + tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); + tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0); + tcg_gen_mov_i32(TCGV_HIGH(ret), t1); + } else { + tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); + /* Note: ret can be the same as arg1, so we use t1 */ + tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c); + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); + tcg_gen_mov_i32(TCGV_LOW(ret), t1); + } + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + } +} +#endif + +static void tcg_reg_alloc_start(TCGContext *s) +{ + int i; + TCGTemp *ts; + for(i = 0; i < s->nb_globals; i++) { + ts = &s->temps[i]; + if (ts->fixed_reg) { + ts->val_type = TEMP_VAL_REG; + } else { + ts->val_type = TEMP_VAL_MEM; + } + } + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + ts->val_type = TEMP_VAL_DEAD; + ts->mem_allocated = 0; + ts->fixed_reg = 0; + } + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + s->reg_to_temp[i] = -1; + } +} + +static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, + int idx) +{ + TCGTemp *ts; + + ts = &s->temps[idx]; + if (idx < s->nb_globals) { + pstrcpy(buf, buf_size, ts->name); + } else { + if (ts->temp_local) + snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); + else + snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); + } + return buf; +} + +char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg)); +} + +char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg)); +} + +static int helper_cmp(const void *p1, const void *p2) +{ + const TCGHelperInfo *th1 = p1; + const TCGHelperInfo *th2 = p2; + if (th1->func < th2->func) + return -1; + else if (th1->func == th2->func) + return 0; + else + return 1; +} + +/* find helper definition (Note: A hash table would be better) */ +static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) +{ + int m, m_min, m_max; + TCGHelperInfo *th; + tcg_target_ulong v; + + if (unlikely(!s->helpers_sorted)) { + qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), + helper_cmp); + s->helpers_sorted = 1; + } + + /* binary search */ + m_min = 0; + m_max = s->nb_helpers - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + th = &s->helpers[m]; + v = th->func; + if (v == val) + return th; + else if (val < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return NULL; +} + +static const char * const cond_name[] = +{ + [TCG_COND_EQ] = "eq", + [TCG_COND_NE] = "ne", + [TCG_COND_LT] = "lt", + [TCG_COND_GE] = "ge", + [TCG_COND_LE] = "le", + [TCG_COND_GT] = "gt", + [TCG_COND_LTU] = "ltu", + [TCG_COND_GEU] = "geu", + [TCG_COND_LEU] = "leu", + [TCG_COND_GTU] = "gtu" +}; + +void tcg_dump_ops(TCGContext *s, FILE *outfile) +{ + const uint16_t *opc_ptr; + const TCGArg *args; + TCGArg arg; + int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; + const TCGOpDef *def; + char buf[128]; + + first_insn = 1; + opc_ptr = gen_opc_buf; + args = gen_opparam_buf; + while (opc_ptr < gen_opc_ptr) { + c = *opc_ptr++; + def = &tcg_op_defs[c]; + if (c == INDEX_op_debug_insn_start) { + uint64_t pc; +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + pc = ((uint64_t)args[1] << 32) | args[0]; +#else + pc = args[0]; +#endif + if (!first_insn) + fprintf(outfile, "\n"); + fprintf(outfile, " ---- 0x%" PRIx64, pc); + first_insn = 0; + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } else if (c == INDEX_op_call) { + TCGArg arg; + + /* variable number of arguments */ + arg = *args++; + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_cargs = def->nb_cargs; + + fprintf(outfile, " %s ", def->name); + + /* function name */ + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); + /* flags */ + fprintf(outfile, ",$0x%" TCG_PRIlx, + args[nb_oargs + nb_iargs]); + /* nb out args */ + fprintf(outfile, ",$%d", nb_oargs); + for(i = 0; i < nb_oargs; i++) { + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); + } + for(i = 0; i < (nb_iargs - 1); i++) { + fprintf(outfile, ","); + if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { + fprintf(outfile, ""); + } else { + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); + } + } + } else if (c == INDEX_op_movi_i32 +#if TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_movi_i64 +#endif + ) { + tcg_target_ulong val; + TCGHelperInfo *th; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + fprintf(outfile, " %s %s,$", def->name, + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); + val = args[1]; + th = tcg_find_helper(s, val); + if (th) { + fprintf(outfile, "%s", th->name); + } else { + if (c == INDEX_op_movi_i32) + fprintf(outfile, "0x%x", (uint32_t)val); + else + fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); + } + } else { + fprintf(outfile, " %s ", def->name); + if (c == INDEX_op_nopn) { + /* variable number of arguments */ + nb_cargs = *args; + nb_oargs = 0; + nb_iargs = 0; + } else { + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } + + k = 0; + for(i = 0; i < nb_oargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + for(i = 0; i < nb_iargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + if (c == INDEX_op_brcond_i32 +#if TCG_TARGET_REG_BITS == 32 + || c == INDEX_op_brcond2_i32 +#elif TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_brcond_i64 +#endif + ) { + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) + fprintf(outfile, ",%s", cond_name[args[k++]]); + else + fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); + i = 1; + } + else + i = 0; + for(; i < nb_cargs; i++) { + if (k != 0) + fprintf(outfile, ","); + arg = args[k++]; + fprintf(outfile, "$0x%" TCG_PRIlx, arg); + } + } + fprintf(outfile, "\n"); + args += nb_iargs + nb_oargs + nb_cargs; + } +} + +/* we give more priority to constraints with less registers */ +static int get_constraint_priority(const TCGOpDef *def, int k) +{ + const TCGArgConstraint *arg_ct; + + int i, n; + arg_ct = &def->args_ct[k]; + if (arg_ct->ct & TCG_CT_ALIAS) { + /* an alias is equivalent to a single register */ + n = 1; + } else { + if (!(arg_ct->ct & TCG_CT_REG)) + return 0; + n = 0; + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (tcg_regset_test_reg(arg_ct->u.regs, i)) + n++; + } + } + return TCG_TARGET_NB_REGS - n + 1; +} + +/* sort from highest priority to lowest */ +static void sort_constraints(TCGOpDef *def, int start, int n) +{ + int i, j, p1, p2, tmp; + + for(i = 0; i < n; i++) + def->sorted_args[start + i] = start + i; + if (n <= 1) + return; + for(i = 0; i < n - 1; i++) { + for(j = i + 1; j < n; j++) { + p1 = get_constraint_priority(def, def->sorted_args[start + i]); + p2 = get_constraint_priority(def, def->sorted_args[start + j]); + if (p1 < p2) { + tmp = def->sorted_args[start + i]; + def->sorted_args[start + i] = def->sorted_args[start + j]; + def->sorted_args[start + j] = tmp; + } + } + } +} + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) +{ + int op; + TCGOpDef *def; + const char *ct_str; + int i, nb_args; + + for(;;) { + if (tdefs->op < 0) + break; + op = tdefs->op; + assert(op >= 0 && op < NB_OPS); + def = &tcg_op_defs[op]; + nb_args = def->nb_iargs + def->nb_oargs; + for(i = 0; i < nb_args; i++) { + ct_str = tdefs->args_ct_str[i]; + tcg_regset_clear(def->args_ct[i].u.regs); + def->args_ct[i].ct = 0; + if (ct_str[0] >= '0' && ct_str[0] <= '9') { + int oarg; + oarg = ct_str[0] - '0'; + assert(oarg < def->nb_oargs); + assert(def->args_ct[oarg].ct & TCG_CT_REG); + /* TCG_CT_ALIAS is for the output arguments. The input + argument is tagged with TCG_CT_IALIAS. */ + def->args_ct[i] = def->args_ct[oarg]; + def->args_ct[oarg].ct = TCG_CT_ALIAS; + def->args_ct[oarg].alias_index = i; + def->args_ct[i].ct |= TCG_CT_IALIAS; + def->args_ct[i].alias_index = oarg; + } else { + for(;;) { + if (*ct_str == '\0') + break; + switch(*ct_str) { + case 'i': + def->args_ct[i].ct |= TCG_CT_CONST; + ct_str++; + break; + default: + if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { + fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", + ct_str, i, def->name); + exit(1); + } + } + } + } + } + + /* sort the constraints (XXX: this is just an heuristic) */ + sort_constraints(def, 0, def->nb_oargs); + sort_constraints(def, def->nb_oargs, def->nb_iargs); + +#if 0 + { + int i; + + printf("%s: sorted=", def->name); + for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) + printf(" %d", def->sorted_args[i]); + printf("\n"); + } +#endif + tdefs++; + } + +} + +#ifdef USE_LIVENESS_ANALYSIS + +/* set a nop for an operation using 'nb_args' */ +static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, + TCGArg *args, int nb_args) +{ + if (nb_args == 0) { + *opc_ptr = INDEX_op_nop; + } else { + *opc_ptr = INDEX_op_nopn; + args[0] = nb_args; + args[nb_args - 1] = nb_args; + } +} + +/* liveness analysis: end of function: globals are live, temps are + dead. */ +/* XXX: at this stage, not used as there would be little gains because + most TBs end with a conditional jump. */ +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) +{ + memset(dead_temps, 0, s->nb_globals); + memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); +} + +/* liveness analysis: end of basic block: globals are live, temps are + dead, local temps are live. */ +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) +{ + int i; + TCGTemp *ts; + + memset(dead_temps, 0, s->nb_globals); + ts = &s->temps[s->nb_globals]; + for(i = s->nb_globals; i < s->nb_temps; i++) { + if (ts->temp_local) + dead_temps[i] = 0; + else + dead_temps[i] = 1; + ts++; + } +} + +/* Liveness analysis : update the opc_dead_iargs array to tell if a + given input arguments is dead. Instructions updating dead + temporaries are removed. */ +static void tcg_liveness_analysis(TCGContext *s) +{ + int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + TCGArg *args; + const TCGOpDef *def; + uint8_t *dead_temps; + unsigned int dead_iargs; + + gen_opc_ptr++; /* skip end */ + + nb_ops = gen_opc_ptr - gen_opc_buf; + + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); + + dead_temps = tcg_malloc(s->nb_temps); + memset(dead_temps, 1, s->nb_temps); + + args = gen_opparam_ptr; + op_index = nb_ops - 1; + while (op_index >= 0) { + op = gen_opc_buf[op_index]; + def = &tcg_op_defs[op]; + switch(op) { + case INDEX_op_call: + { + int call_flags; + + nb_args = args[-1]; + args -= nb_args; + nb_iargs = args[0] & 0xffff; + nb_oargs = args[0] >> 16; + args++; + call_flags = args[nb_oargs + nb_iargs]; + + /* pure functions can be removed if their result is not + used */ + if (call_flags & TCG_CALL_PURE) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove_call; + } + tcg_set_nop(s, gen_opc_buf + op_index, + args - 1, nb_args); + } else { + do_not_remove_call: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + if (!(call_flags & TCG_CALL_CONST)) { + /* globals are live (they may be used by the call) */ + memset(dead_temps, 0, s->nb_globals); + } + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (arg != TCG_CALL_DUMMY_ARG) { + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + } + s->op_dead_iargs[op_index] = dead_iargs; + } + args--; + } + break; + case INDEX_op_set_label: + args--; + /* mark end of basic block */ + tcg_la_bb_end(s, dead_temps); + break; + case INDEX_op_debug_insn_start: + args -= def->nb_args; + break; + case INDEX_op_nopn: + nb_args = args[-1]; + args -= nb_args; + break; + case INDEX_op_discard: + args--; + /* mark the temporary as dead */ + dead_temps[args[0]] = 1; + break; + case INDEX_op_end: + break; + /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ + default: + args -= def->nb_args; + nb_iargs = def->nb_iargs; + nb_oargs = def->nb_oargs; + + /* Test if the operation can be removed because all + its outputs are dead. We assume that nb_oargs == 0 + implies side effects */ + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove; + } + tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); +#ifdef CONFIG_PROFILER + s->del_op_count++; +#endif + } else { + do_not_remove: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + /* if end of basic block, update */ + if (def->flags & TCG_OPF_BB_END) { + tcg_la_bb_end(s, dead_temps); + } else if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* globals are live */ + memset(dead_temps, 0, s->nb_globals); + } + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + s->op_dead_iargs[op_index] = dead_iargs; + } + break; + } + op_index--; + } + + if (args != gen_opparam_buf) + tcg_abort(); +} +#else +/* dummy liveness analysis */ +void tcg_liveness_analysis(TCGContext *s) +{ + int nb_ops; + nb_ops = gen_opc_ptr - gen_opc_buf; + + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); + memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t)); +} +#endif + +#ifndef NDEBUG +static void dump_regs(TCGContext *s) +{ + TCGTemp *ts; + int i; + char buf[64]; + + for(i = 0; i < s->nb_temps; i++) { + ts = &s->temps[i]; + printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); + switch(ts->val_type) { + case TEMP_VAL_REG: + printf("%s", tcg_target_reg_names[ts->reg]); + break; + case TEMP_VAL_MEM: + printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); + break; + case TEMP_VAL_CONST: + printf("$0x%" TCG_PRIlx, ts->val); + break; + case TEMP_VAL_DEAD: + printf("D"); + break; + default: + printf("???"); + break; + } + printf("\n"); + } + + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (s->reg_to_temp[i] >= 0) { + printf("%s: %s\n", + tcg_target_reg_names[i], + tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); + } + } +} + +static void check_regs(TCGContext *s) +{ + int reg, k; + TCGTemp *ts; + char buf[64]; + + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + k = s->reg_to_temp[reg]; + if (k >= 0) { + ts = &s->temps[k]; + if (ts->val_type != TEMP_VAL_REG || + ts->reg != reg) { + printf("Inconsistency for register %s:\n", + tcg_target_reg_names[reg]); + goto fail; + } + } + } + for(k = 0; k < s->nb_temps; k++) { + ts = &s->temps[k]; + if (ts->val_type == TEMP_VAL_REG && + !ts->fixed_reg && + s->reg_to_temp[ts->reg] != k) { + printf("Inconsistency for temp %s:\n", + tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); + fail: + printf("reg state:\n"); + dump_regs(s); + tcg_abort(); + } + } +} +#endif + +static void temp_allocate_frame(TCGContext *s, int temp) +{ + TCGTemp *ts; + ts = &s->temps[temp]; + s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); + if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) + tcg_abort(); + ts->mem_offset = s->current_frame_offset; + ts->mem_reg = s->frame_reg; + ts->mem_allocated = 1; + s->current_frame_offset += sizeof(tcg_target_long); +} + +/* free register 'reg' by spilling the corresponding temporary if necessary */ +static void tcg_reg_free(TCGContext *s, int reg) +{ + TCGTemp *ts; + int temp; + + temp = s->reg_to_temp[reg]; + if (temp != -1) { + ts = &s->temps[temp]; + assert(ts->val_type == TEMP_VAL_REG); + if (!ts->mem_coherent) { + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } + ts->val_type = TEMP_VAL_MEM; + s->reg_to_temp[reg] = -1; + } +} + +/* Allocate a register belonging to reg1 & ~reg2 */ +static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) +{ + int i, reg; + TCGRegSet reg_ct; + + tcg_regset_andnot(reg_ct, reg1, reg2); + + /* first try free registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) + return reg; + } + + /* XXX: do better spill choice */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg)) { + tcg_reg_free(s, reg); + return reg; + } + } + + tcg_abort(); +} + +/* save a temporary to memory. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int reg; + + ts = &s->temps[temp]; + if (!ts->fixed_reg) { + switch(ts->val_type) { + case TEMP_VAL_REG: + tcg_reg_free(s, ts->reg); + break; + case TEMP_VAL_DEAD: + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_CONST: + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + allocated_regs); + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_MEM: + break; + default: + tcg_abort(); + } + } +} + +/* save globals to their cannonical location and assume they can be + modified be the following code. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void save_globals(TCGContext *s, TCGRegSet allocated_regs) +{ + int i; + + for(i = 0; i < s->nb_globals; i++) { + temp_save(s, i, allocated_regs); + } +} + +/* at the end of a basic block, we assume all temporaries are dead and + all globals are stored at their canonical location. */ +static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int i; + + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + if (ts->temp_local) { + temp_save(s, i, allocated_regs); + } else { + if (ts->val_type == TEMP_VAL_REG) { + s->reg_to_temp[ts->reg] = -1; + } + ts->val_type = TEMP_VAL_DEAD; + } + } + + save_globals(s, allocated_regs); +} + +#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) + +static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) +{ + TCGTemp *ots; + tcg_target_ulong val; + + ots = &s->temps[args[0]]; + val = args[1]; + + if (ots->fixed_reg) { + /* for fixed registers, we do not do any constant + propagation */ + tcg_out_movi(s, ots->type, ots->reg, val); + } else { + /* The movi is not explicitly generated here */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = val; + } +} + +static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGTemp *ts, *ots; + int reg; + const TCGArgConstraint *arg_ct; + + ots = &s->temps[args[0]]; + ts = &s->temps[args[1]]; + arg_ct = &def->args_ct[0]; + + /* XXX: always mark arg dead if IS_DEAD_IARG(0) */ + if (ts->val_type == TEMP_VAL_REG) { + if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { + /* the mov can be suppressed */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + reg = ts->reg; + s->reg_to_temp[reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } else { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } + } else if (ts->val_type == TEMP_VAL_MEM) { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (ots->fixed_reg) { + reg = ots->reg; + tcg_out_movi(s, ots->type, reg, ts->val); + } else { + /* propagate constant */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = ts->val; + return; + } + } else { + tcg_abort(); + } + s->reg_to_temp[reg] = args[0]; + ots->reg = reg; + ots->val_type = TEMP_VAL_REG; + ots->mem_coherent = 0; +} + +static void tcg_reg_alloc_op(TCGContext *s, + const TCGOpDef *def, int opc, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGRegSet allocated_regs; + int i, k, nb_iargs, nb_oargs, reg; + TCGArg arg; + const TCGArgConstraint *arg_ct; + TCGTemp *ts; + TCGArg new_args[TCG_MAX_OP_ARGS]; + int const_args[TCG_MAX_OP_ARGS]; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + + /* copy constants */ + memcpy(new_args + nb_oargs + nb_iargs, + args + nb_oargs + nb_iargs, + sizeof(TCGArg) * def->nb_cargs); + + /* satisfy input constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_iargs; k++) { + i = def->sorted_args[nb_oargs + k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 1; + s->reg_to_temp[reg] = arg; + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(ts->val, arg_ct)) { + /* constant is OK for instruction */ + const_args[i] = 1; + new_args[i] = ts->val; + goto iarg_end; + } else { + /* need to move to a register */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, ts->val); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + assert(ts->val_type == TEMP_VAL_REG); + if (arg_ct->ct & TCG_CT_IALIAS) { + if (ts->fixed_reg) { + /* if fixed register, we must allocate a new register + if the alias is not the same register */ + if (arg != args[arg_ct->alias_index]) + goto allocate_in_reg; + } else { + /* if the input is aliased to an output and if it is + not dead after the instruction, we must allocate + a new register and move it */ + if (!IS_DEAD_IARG(i - nb_oargs)) + goto allocate_in_reg; + } + } + reg = ts->reg; + if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { + /* nothing to do : the constraint is satisfied */ + } else { + allocate_in_reg: + /* allocate a new register matching the constraint + and move the temporary register into it */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + new_args[i] = reg; + const_args[i] = 0; + tcg_regset_set_reg(allocated_regs, reg); + iarg_end: ; + } + + if (def->flags & TCG_OPF_BB_END) { + tcg_reg_alloc_bb_end(s, allocated_regs); + } else { + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* XXX: permit generic clobber register list ? */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + /* XXX: for load/store we could do that only for the slow path + (i.e. when a memory callback is called) */ + + /* store globals and free associated registers (we assume the insn + can modify any global. */ + save_globals(s, allocated_regs); + } + + /* satisfy the output constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_oargs; k++) { + i = def->sorted_args[k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (arg_ct->ct & TCG_CT_ALIAS) { + reg = new_args[arg_ct->alias_index]; + } else { + /* if fixed register, we try to use it */ + reg = ts->reg; + if (ts->fixed_reg && + tcg_regset_test_reg(arg_ct->u.regs, reg)) { + goto oarg_end; + } + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + } + tcg_regset_set_reg(allocated_regs, reg); + /* if a fixed register is used, then a move will be done afterwards */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + /* temp value is modified, so the value kept in memory is + potentially not the same */ + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + oarg_end: + new_args[i] = reg; + } + } + + /* emit instruction */ + tcg_out_op(s, opc, new_args, const_args); + + /* move the outputs in the correct register if needed */ + for(i = 0; i < nb_oargs; i++) { + ts = &s->temps[args[i]]; + reg = new_args[i]; + if (ts->fixed_reg && ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } +} + +#ifdef TCG_TARGET_STACK_GROWSUP +#define STACK_DIR(x) (-(x)) +#else +#define STACK_DIR(x) (x) +#endif + +static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, + int opc, const TCGArg *args, + unsigned int dead_iargs) +{ + int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; + TCGArg arg, func_arg; + TCGTemp *ts; + tcg_target_long stack_offset, call_stack_size, func_addr; + int const_func_arg, allocate_args; + TCGRegSet allocated_regs; + const TCGArgConstraint *arg_ct; + + arg = *args++; + + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_params = nb_iargs - 1; + + flags = args[nb_oargs + nb_iargs]; + + nb_regs = tcg_target_get_call_iarg_regs_count(flags); + if (nb_regs > nb_params) + nb_regs = nb_params; + + /* assign stack slots first */ + /* XXX: preallocate call stack */ + call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); + call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); + } + + stack_offset = TCG_TARGET_CALL_STACK_OFFSET; + for(i = nb_regs; i < nb_params; i++) { + arg = args[nb_oargs + i]; +#ifdef TCG_TARGET_STACK_GROWSUP + stack_offset -= sizeof(tcg_target_long); +#endif + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_REG) { + tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: not correct if reading values from the stack */ + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: sign extend may be needed on some targets */ + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else { + tcg_abort(); + } + } +#ifndef TCG_TARGET_STACK_GROWSUP + stack_offset += sizeof(tcg_target_long); +#endif + } + + /* assign input registers */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(i = 0; i < nb_regs; i++) { + arg = args[nb_oargs + i]; + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + reg = tcg_target_call_iarg_regs[i]; + tcg_reg_free(s, reg); + if (ts->val_type == TEMP_VAL_REG) { + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } else if (ts->val_type == TEMP_VAL_MEM) { + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + /* XXX: sign extend ? */ + tcg_out_movi(s, ts->type, reg, ts->val); + } else { + tcg_abort(); + } + tcg_regset_set_reg(allocated_regs, reg); + } + } + + /* assign function address */ + func_arg = args[nb_oargs + nb_iargs - 1]; + arg_ct = &def->args_ct[0]; + ts = &s->temps[func_arg]; + func_addr = ts->val; + const_func_arg = 0; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_REG) { + reg = ts->reg; + if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(func_addr, arg_ct)) { + const_func_arg = 1; + func_arg = func_addr; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, func_addr); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } + } else { + tcg_abort(); + } + + + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + /* clobber call registers */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + + /* store globals and free associated registers (we assume the call + can modify any global. */ + if (!(flags & TCG_CALL_CONST)) { + save_globals(s, allocated_regs); + } + + tcg_out_op(s, opc, &func_arg, &const_func_arg); + + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); + } + + /* assign output registers and emit moves if needed */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + ts = &s->temps[arg]; + reg = tcg_target_call_oarg_regs[i]; + assert(s->reg_to_temp[reg] == -1); + if (ts->fixed_reg) { + if (ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } else { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + + return nb_iargs + nb_oargs + def->nb_cargs + 1; +} + +#ifdef CONFIG_PROFILER + +static int64_t tcg_table_op_count[NB_OPS]; + +static void dump_op_count(void) +{ + int i; + FILE *f; + f = fopen("/tmp/op.log", "w"); + for(i = INDEX_op_end; i < NB_OPS; i++) { + fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]); + } + fclose(f); +} +#endif + + +static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, + long search_pc) +{ + int opc, op_index; + const TCGOpDef *def; + unsigned int dead_iargs; + const TCGArg *args; + +#ifdef DEBUG_DISAS + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + qemu_log("OP:\n"); + tcg_dump_ops(s, logfile); + qemu_log("\n"); + } +#endif + +#ifdef CONFIG_PROFILER + s->la_time -= profile_getclock(); +#endif + tcg_liveness_analysis(s); +#ifdef CONFIG_PROFILER + s->la_time += profile_getclock(); +#endif + +#ifdef DEBUG_DISAS + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { + qemu_log("OP after liveness analysis:\n"); + tcg_dump_ops(s, logfile); + qemu_log("\n"); + } +#endif + + tcg_reg_alloc_start(s); + + s->code_buf = gen_code_buf; + s->code_ptr = gen_code_buf; + + args = gen_opparam_buf; + op_index = 0; + + for(;;) { + opc = gen_opc_buf[op_index]; +#ifdef CONFIG_PROFILER + tcg_table_op_count[opc]++; +#endif + def = &tcg_op_defs[opc]; +#if 0 + printf("%s: %d %d %d\n", def->name, + def->nb_oargs, def->nb_iargs, def->nb_cargs); + // dump_regs(s); +#endif + switch(opc) { + case INDEX_op_mov_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_mov_i64: +#endif + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_mov(s, def, args, dead_iargs); + break; + case INDEX_op_movi_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: +#endif + tcg_reg_alloc_movi(s, args); + break; + case INDEX_op_debug_insn_start: + /* debug instruction */ + break; + case INDEX_op_nop: + case INDEX_op_nop1: + case INDEX_op_nop2: + case INDEX_op_nop3: + break; + case INDEX_op_nopn: + args += args[0]; + goto next; + case INDEX_op_discard: + { + TCGTemp *ts; + ts = &s->temps[args[0]]; + /* mark the temporary as dead */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + break; + case INDEX_op_set_label: + tcg_reg_alloc_bb_end(s, s->reserved_regs); + tcg_out_label(s, args[0], (long)s->code_ptr); + break; + case INDEX_op_call: + dead_iargs = s->op_dead_iargs[op_index]; + args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); + goto next; + case INDEX_op_end: + goto the_end; + default: + /* Note: in order to speed up the code, it would be much + faster to have specialized register allocator functions for + some common argument patterns */ + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_op(s, def, opc, args, dead_iargs); + break; + } + args += def->nb_args; + next: + if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { + return op_index; + } + op_index++; +#ifndef NDEBUG + check_regs(s); +#endif + } + the_end: + return -1; +} + +int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) +{ +#ifdef CONFIG_PROFILER + { + int n; + n = (gen_opc_ptr - gen_opc_buf); + s->op_count += n; + if (n > s->op_count_max) + s->op_count_max = n; + + s->temp_count += s->nb_temps; + if (s->nb_temps > s->temp_count_max) + s->temp_count_max = s->nb_temps; + } +#endif + + tcg_gen_code_common(s, gen_code_buf, -1); + + /* flush instruction cache */ + flush_icache_range((unsigned long)gen_code_buf, + (unsigned long)s->code_ptr); + return s->code_ptr - gen_code_buf; +} + +/* Return the index of the micro operation such as the pc after is < + offset bytes from the start of the TB. The contents of gen_code_buf must + not be changed, though writing the same values is ok. + Return -1 if not found. */ +int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) +{ + return tcg_gen_code_common(s, gen_code_buf, offset); +} + +#ifdef CONFIG_PROFILER +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + TCGContext *s = &tcg_ctx; + int64_t tot; + + tot = s->interm_time + s->code_time; + cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", + tot, tot / 2.4e9); + cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", + s->tb_count, + s->tb_count1 - s->tb_count, + s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); + cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", + s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); + cpu_fprintf(f, "deleted ops/TB %0.2f\n", + s->tb_count ? + (double)s->del_op_count / s->tb_count : 0); + cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", + s->tb_count ? + (double)s->temp_count / s->tb_count : 0, + s->temp_count_max); + + cpu_fprintf(f, "cycles/op %0.1f\n", + s->op_count ? (double)tot / s->op_count : 0); + cpu_fprintf(f, "cycles/in byte %0.1f\n", + s->code_in_len ? (double)tot / s->code_in_len : 0); + cpu_fprintf(f, "cycles/out byte %0.1f\n", + s->code_out_len ? (double)tot / s->code_out_len : 0); + if (tot == 0) + tot = 1; + cpu_fprintf(f, " gen_interm time %0.1f%%\n", + (double)s->interm_time / tot * 100.0); + cpu_fprintf(f, " gen_code time %0.1f%%\n", + (double)s->code_time / tot * 100.0); + cpu_fprintf(f, "liveness/code time %0.1f%%\n", + (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); + cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", + s->restore_count); + cpu_fprintf(f, " avg cycles %0.1f\n", + s->restore_count ? (double)s->restore_time / s->restore_count : 0); + + dump_op_count(); +} +#else +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + cpu_fprintf(f, "[TCG profiler not compiled]\n"); +} +#endif diff --git a/qemu/qemu-git/tcg/.svn/text-base/tcg.h.svn-base b/qemu/qemu-git/tcg/.svn/text-base/tcg.h.svn-base new file mode 100644 index 0000000..121b17c --- /dev/null +++ b/qemu/qemu-git/tcg/.svn/text-base/tcg.h.svn-base @@ -0,0 +1,468 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "tcg-target.h" +#include "tcg-runtime.h" + +#if TCG_TARGET_REG_BITS == 32 +typedef int32_t tcg_target_long; +typedef uint32_t tcg_target_ulong; +#define TCG_PRIlx PRIx32 +#define TCG_PRIld PRId32 +#elif TCG_TARGET_REG_BITS == 64 +typedef int64_t tcg_target_long; +typedef uint64_t tcg_target_ulong; +#define TCG_PRIlx PRIx64 +#define TCG_PRIld PRId64 +#else +#error unsupported +#endif + +#if TCG_TARGET_NB_REGS <= 32 +typedef uint32_t TCGRegSet; +#elif TCG_TARGET_NB_REGS <= 64 +typedef uint64_t TCGRegSet; +#else +#error unsupported +#endif + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "tcg-opc.h" +#undef DEF + NB_OPS, +}; + +#define tcg_regset_clear(d) (d) = 0 +#define tcg_regset_set(d, s) (d) = (s) +#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg) +#define tcg_regset_set_reg(d, r) (d) |= 1L << (r) +#define tcg_regset_reset_reg(d, r) (d) &= ~(1L << (r)) +#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1) +#define tcg_regset_or(d, a, b) (d) = (a) | (b) +#define tcg_regset_and(d, a, b) (d) = (a) & (b) +#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b) +#define tcg_regset_not(d, a) (d) = ~(a) + +typedef struct TCGRelocation { + struct TCGRelocation *next; + int type; + uint8_t *ptr; + tcg_target_long addend; +} TCGRelocation; + +typedef struct TCGLabel { + int has_value; + union { + tcg_target_ulong value; + TCGRelocation *first_reloc; + } u; +} TCGLabel; + +typedef struct TCGPool { + struct TCGPool *next; + int size; + uint8_t data[0] __attribute__ ((aligned)); +} TCGPool; + +#define TCG_POOL_CHUNK_SIZE 32768 + +#define TCG_MAX_LABELS 512 + +#define TCG_MAX_TEMPS 512 + +/* when the size of the arguments of a called function is smaller than + this value, they are statically allocated in the TB stack frame */ +#define TCG_STATIC_CALL_ARGS_SIZE 128 + +typedef int TCGType; + +#define TCG_TYPE_I32 0 +#define TCG_TYPE_I64 1 +#define TCG_TYPE_COUNT 2 /* number of different types */ + +#if TCG_TARGET_REG_BITS == 32 +#define TCG_TYPE_PTR TCG_TYPE_I32 +#else +#define TCG_TYPE_PTR TCG_TYPE_I64 +#endif + +typedef tcg_target_ulong TCGArg; + +/* Define a type and accessor macros for varables. Using a struct is + nice because it gives some level of type safely. Ideally the compiler + be able to see through all this. However in practice this is not true, + expecially on targets with braindamaged ABIs (e.g. i386). + We use plain int by default to avoid this runtime overhead. + Users of tcg_gen_* don't need to know about any of this, and should + treat TCGv as an opaque type. + In additon we do typechecking for different types of variables. TCGv_i32 + and TCGv_i64 are 32/64-bit variables respectively. TCGv and TCGv_ptr + are aliases for target_ulong and host pointer sized values respectively. + */ + +#ifdef CONFIG_DEBUG_TCG +#define DEBUG_TCGV 1 +#endif + +#ifdef DEBUG_TCGV + +typedef struct +{ + int i32; +} TCGv_i32; + +typedef struct +{ + int i64; +} TCGv_i64; + +#define MAKE_TCGV_I32(i) __extension__ \ + ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;}) +#define MAKE_TCGV_I64(i) __extension__ \ + ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;}) +#define GET_TCGV_I32(t) ((t).i32) +#define GET_TCGV_I64(t) ((t).i64) +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t)) +#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1) +#endif + +#else /* !DEBUG_TCGV */ + +typedef int TCGv_i32; +typedef int TCGv_i64; +#define MAKE_TCGV_I32(x) (x) +#define MAKE_TCGV_I64(x) (x) +#define GET_TCGV_I32(t) (t) +#define GET_TCGV_I64(t) (t) + +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_LOW(t) (t) +#define TCGV_HIGH(t) ((t) + 1) +#endif + +#endif /* DEBUG_TCGV */ + +#define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b)) +#define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b)) + +/* Dummy definition to avoid compiler warnings. */ +#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1) +#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) + +/* call flags */ +#define TCG_CALL_TYPE_MASK 0x000f +#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */ +#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */ +#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */ +#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */ +/* A pure function only reads its arguments and TCG global variables + and cannot raise exceptions. Hence a call to a pure function can be + safely suppressed if the return value is not used. */ +#define TCG_CALL_PURE 0x0010 +/* A const function only reads its arguments and does not use TCG + global variables. Hence a call to such a function does not + save TCG global variables back to their canonical location. */ +#define TCG_CALL_CONST 0x0020 + +/* used to align parameters */ +#define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) +#define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) + +typedef enum { + TCG_COND_EQ, + TCG_COND_NE, + TCG_COND_LT, + TCG_COND_GE, + TCG_COND_LE, + TCG_COND_GT, + /* unsigned */ + TCG_COND_LTU, + TCG_COND_GEU, + TCG_COND_LEU, + TCG_COND_GTU, +} TCGCond; + +static inline TCGCond tcg_unsigned_cond(TCGCond c) +{ + return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c); +} + +#define TEMP_VAL_DEAD 0 +#define TEMP_VAL_REG 1 +#define TEMP_VAL_MEM 2 +#define TEMP_VAL_CONST 3 + +/* XXX: optimize memory layout */ +typedef struct TCGTemp { + TCGType base_type; + TCGType type; + int val_type; + int reg; + tcg_target_long val; + int mem_reg; + tcg_target_long mem_offset; + unsigned int fixed_reg:1; + unsigned int mem_coherent:1; + unsigned int mem_allocated:1; + unsigned int temp_local:1; /* If true, the temp is saved accross + basic blocks. Otherwise, it is not + preserved accross basic blocks. */ + unsigned int temp_allocated:1; /* never used for code gen */ + /* index of next free temp of same base type, -1 if end */ + int next_free_temp; + const char *name; +} TCGTemp; + +typedef struct TCGHelperInfo { + tcg_target_ulong func; + const char *name; +} TCGHelperInfo; + +typedef struct TCGContext TCGContext; + +struct TCGContext { + uint8_t *pool_cur, *pool_end; + TCGPool *pool_first, *pool_current; + TCGLabel *labels; + int nb_labels; + TCGTemp *temps; /* globals first, temps after */ + int nb_globals; + int nb_temps; + /* index of free temps, -1 if none */ + int first_free_temp[TCG_TYPE_COUNT * 2]; + + /* goto_tb support */ + uint8_t *code_buf; + unsigned long *tb_next; + uint16_t *tb_next_offset; + uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ + + /* liveness analysis */ + uint16_t *op_dead_iargs; /* for each operation, each bit tells if the + corresponding input argument is dead */ + + /* tells in which temporary a given register is. It does not take + into account fixed registers */ + int reg_to_temp[TCG_TARGET_NB_REGS]; + TCGRegSet reserved_regs; + tcg_target_long current_frame_offset; + tcg_target_long frame_start; + tcg_target_long frame_end; + int frame_reg; + + uint8_t *code_ptr; + TCGTemp static_temps[TCG_MAX_TEMPS]; + + TCGHelperInfo *helpers; + int nb_helpers; + int allocated_helpers; + int helpers_sorted; + +#ifdef CONFIG_PROFILER + /* profiling info */ + int64_t tb_count1; + int64_t tb_count; + int64_t op_count; /* total insn count */ + int op_count_max; /* max insn per TB */ + int64_t temp_count; + int temp_count_max; + int64_t del_op_count; + int64_t code_in_len; + int64_t code_out_len; + int64_t interm_time; + int64_t code_time; + int64_t la_time; + int64_t restore_count; + int64_t restore_time; +#endif +}; + +extern TCGContext tcg_ctx; +extern uint16_t *gen_opc_ptr; +extern TCGArg *gen_opparam_ptr; +extern uint16_t gen_opc_buf[]; +extern TCGArg gen_opparam_buf[]; + +/* pool based memory allocation */ + +void *tcg_malloc_internal(TCGContext *s, int size); +void tcg_pool_reset(TCGContext *s); +void tcg_pool_delete(TCGContext *s); + +static inline void *tcg_malloc(int size) +{ + TCGContext *s = &tcg_ctx; + uint8_t *ptr, *ptr_end; + size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1); + ptr = s->pool_cur; + ptr_end = ptr + size; + if (unlikely(ptr_end > s->pool_end)) { + return tcg_malloc_internal(&tcg_ctx, size); + } else { + s->pool_cur = ptr_end; + return ptr; + } +} + +void tcg_context_init(TCGContext *s); +void tcg_func_start(TCGContext *s); + +int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf); +int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset); + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size); + +TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name); +TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, + const char *name); +TCGv_i32 tcg_temp_new_internal_i32(int temp_local); +static inline TCGv_i32 tcg_temp_new_i32(void) +{ + return tcg_temp_new_internal_i32(0); +} +static inline TCGv_i32 tcg_temp_local_new_i32(void) +{ + return tcg_temp_new_internal_i32(1); +} +void tcg_temp_free_i32(TCGv_i32 arg); +char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg); + +TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name); +TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, + const char *name); +TCGv_i64 tcg_temp_new_internal_i64(int temp_local); +static inline TCGv_i64 tcg_temp_new_i64(void) +{ + return tcg_temp_new_internal_i64(0); +} +static inline TCGv_i64 tcg_temp_local_new_i64(void) +{ + return tcg_temp_new_internal_i64(1); +} +void tcg_temp_free_i64(TCGv_i64 arg); +char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg); + +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +#define TCG_CT_ALIAS 0x80 +#define TCG_CT_IALIAS 0x40 +#define TCG_CT_REG 0x01 +#define TCG_CT_CONST 0x02 /* any constant of register size */ + +typedef struct TCGArgConstraint { + uint16_t ct; + uint8_t alias_index; + union { + TCGRegSet regs; + } u; +} TCGArgConstraint; + +#define TCG_MAX_OP_ARGS 16 + +#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic + block */ +#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers + and potentially update globals. */ +#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it + cannot be removed if its output + are not used */ + +typedef struct TCGOpDef { + const char *name; + uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args; + uint8_t flags; + uint16_t copy_size; + TCGArgConstraint *args_ct; + int *sorted_args; +} TCGOpDef; + +typedef struct TCGTargetOpDef { + int op; + const char *args_ct_str[TCG_MAX_OP_ARGS]; +} TCGTargetOpDef; + +void tcg_target_init(TCGContext *s); +void tcg_target_qemu_prologue(TCGContext *s); + +#define tcg_abort() \ +do {\ + fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\ + abort();\ +} while (0) + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs); + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_const_ptr tcg_const_i32 +#define tcg_add_ptr tcg_add_i32 +#define tcg_sub_ptr tcg_sub_i32 +#define TCGv_ptr TCGv_i32 +#define GET_TCGV_PTR GET_TCGV_I32 +#define tcg_global_reg_new_ptr tcg_global_reg_new_i32 +#define tcg_global_mem_new_ptr tcg_global_mem_new_i32 +#define tcg_temp_new_ptr tcg_temp_new_i32 +#define tcg_temp_free_ptr tcg_temp_free_i32 +#else +#define tcg_const_ptr tcg_const_i64 +#define tcg_add_ptr tcg_add_i64 +#define tcg_sub_ptr tcg_sub_i64 +#define TCGv_ptr TCGv_i64 +#define GET_TCGV_PTR GET_TCGV_I64 +#define tcg_global_reg_new_ptr tcg_global_reg_new_i64 +#define tcg_global_mem_new_ptr tcg_global_mem_new_i64 +#define tcg_temp_new_ptr tcg_temp_new_i64 +#define tcg_temp_free_ptr tcg_temp_free_i64 +#endif + +void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, + int sizemask, TCGArg ret, int nargs, TCGArg *args); + +void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, + int c, int right, int arith); + +/* only used for debugging purposes */ +void tcg_register_helper(void *func, const char *name); +const char *tcg_helper_get_name(TCGContext *s, void *func); +void tcg_dump_ops(TCGContext *s, FILE *outfile); + +void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf); +TCGv_i32 tcg_const_i32(int32_t val); +TCGv_i64 tcg_const_i64(int64_t val); +TCGv_i32 tcg_const_local_i32(int32_t val); +TCGv_i64 tcg_const_local_i64(int64_t val); + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend); + +extern uint8_t code_gen_prologue[]; +#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64) +#define tcg_qemu_tb_exec(tb_ptr) \ + ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr) +#else +#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) +#endif diff --git a/qemu/qemu-git/tcg/LICENSE b/qemu/qemu-git/tcg/LICENSE new file mode 100644 index 0000000..be817fa --- /dev/null +++ b/qemu/qemu-git/tcg/LICENSE @@ -0,0 +1,3 @@ +All the files in this directory and subdirectories are released under +a BSD like license (see header in each file). No other license is +accepted. diff --git a/qemu/qemu-git/tcg/README b/qemu/qemu-git/tcg/README new file mode 100644 index 0000000..e672258 --- /dev/null +++ b/qemu/qemu-git/tcg/README @@ -0,0 +1,454 @@ +Tiny Code Generator - Fabrice Bellard. + +1) Introduction + +TCG (Tiny Code Generator) began as a generic backend for a C +compiler. It was simplified to be used in QEMU. It also has its roots +in the QOP code generator written by Paul Brook. + +2) Definitions + +The TCG "target" is the architecture for which we generate the +code. It is of course not the same as the "target" of QEMU which is +the emulated architecture. As TCG started as a generic C backend used +for cross compiling, it is assumed that the TCG target is different +from the host, although it is never the case for QEMU. + +A TCG "function" corresponds to a QEMU Translated Block (TB). + +A TCG "temporary" is a variable only live in a basic +block. Temporaries are allocated explicitly in each function. + +A TCG "local temporary" is a variable only live in a function. Local +temporaries are allocated explicitly in each function. + +A TCG "global" is a variable which is live in all the functions +(equivalent of a C global variable). They are defined before the +functions defined. A TCG global can be a memory location (e.g. a QEMU +CPU register), a fixed host register (e.g. the QEMU CPU state pointer) +or a memory location which is stored in a register outside QEMU TBs +(not implemented yet). + +A TCG "basic block" corresponds to a list of instructions terminated +by a branch instruction. + +3) Intermediate representation + +3.1) Introduction + +TCG instructions operate on variables which are temporaries, local +temporaries or globals. TCG instructions and variables are strongly +typed. Two types are supported: 32 bit integers and 64 bit +integers. Pointers are defined as an alias to 32 bit or 64 bit +integers depending on the TCG target word size. + +Each instruction has a fixed number of output variable operands, input +variable operands and always constant operands. + +The notable exception is the call instruction which has a variable +number of outputs and inputs. + +In the textual form, output operands usually come first, followed by +input operands, followed by constant operands. The output type is +included in the instruction name. Constants are prefixed with a '$'. + +add_i32 t0, t1, t2 (t0 <- t1 + t2) + +3.2) Assumptions + +* Basic blocks + +- Basic blocks end after branches (e.g. brcond_i32 instruction), + goto_tb and exit_tb instructions. +- Basic blocks start after the end of a previous basic block, or at a + set_label instruction. + +After the end of a basic block, the content of temporaries is +destroyed, but local temporaries and globals are preserved. + +* Floating point types are not supported yet + +* Pointers: depending on the TCG target, pointer size is 32 bit or 64 + bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or + TCG_TYPE_I64. + +* Helpers: + +Using the tcg_gen_helper_x_y it is possible to call any function +taking i32, i64 or pointer types. Before calling an helper, all +globals are stored at their canonical location and it is assumed that +the function can modify them. In the future, function modifiers will +be allowed to tell that the helper does not read or write some globals. + +On some TCG targets (e.g. x86), several calling conventions are +supported. + +* Branches: + +Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an +explicit address. Conditional branches can only jump to labels. + +3.3) Code Optimizations + +When generating instructions, you can count on at least the following +optimizations: + +- Single instructions are simplified, e.g. + + and_i32 t0, t0, $0xffffffff + + is suppressed. + +- A liveness analysis is done at the basic block level. The + information is used to suppress moves from a dead variable to + another one. It is also used to remove instructions which compute + dead results. The later is especially useful for condition code + optimization in QEMU. + + In the following example: + + add_i32 t0, t1, t2 + add_i32 t0, t0, $1 + mov_i32 t0, $1 + + only the last instruction is kept. + +3.4) Instruction Reference + +********* Function call + +* call ptr + +call function 'ptr' (pointer type) + + optional 32 bit or 64 bit return value + optional 32 bit or 64 bit parameters + +********* Jumps/Labels + +* jmp t0 + +Absolute jump to address t0 (pointer type). + +* set_label $label + +Define label 'label' at the current program point. + +* br $label + +Jump to label. + +* brcond_i32/i64 cond, t0, t1, label + +Conditional jump if t0 cond t1 is true. cond can be: + TCG_COND_EQ + TCG_COND_NE + TCG_COND_LT /* signed */ + TCG_COND_GE /* signed */ + TCG_COND_LE /* signed */ + TCG_COND_GT /* signed */ + TCG_COND_LTU /* unsigned */ + TCG_COND_GEU /* unsigned */ + TCG_COND_LEU /* unsigned */ + TCG_COND_GTU /* unsigned */ + +********* Arithmetic + +* add_i32/i64 t0, t1, t2 + +t0=t1+t2 + +* sub_i32/i64 t0, t1, t2 + +t0=t1-t2 + +* neg_i32/i64 t0, t1 + +t0=-t1 (two's complement) + +* mul_i32/i64 t0, t1, t2 + +t0=t1*t2 + +* div_i32/i64 t0, t1, t2 + +t0=t1/t2 (signed). Undefined behavior if division by zero or overflow. + +* divu_i32/i64 t0, t1, t2 + +t0=t1/t2 (unsigned). Undefined behavior if division by zero. + +* rem_i32/i64 t0, t1, t2 + +t0=t1%t2 (signed). Undefined behavior if division by zero or overflow. + +* remu_i32/i64 t0, t1, t2 + +t0=t1%t2 (unsigned). Undefined behavior if division by zero. + +********* Logical + +* and_i32/i64 t0, t1, t2 + +t0=t1&t2 + +* or_i32/i64 t0, t1, t2 + +t0=t1|t2 + +* xor_i32/i64 t0, t1, t2 + +t0=t1^t2 + +* not_i32/i64 t0, t1 + +t0=~t1 + +* andc_i32/i64 t0, t1, t2 + +t0=t1&~t2 + +* eqv_i32/i64 t0, t1, t2 + +t0=~(t1^t2) + +* nand_i32/i64 t0, t1, t2 + +t0=~(t1&t2) + +* nor_i32/i64 t0, t1, t2 + +t0=~(t1|t2) + +* orc_i32/i64 t0, t1, t2 + +t0=t1|~t2 + +********* Shifts/Rotates + +* shl_i32/i64 t0, t1, t2 + +t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* shr_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* sar_i32/i64 t0, t1, t2 + +t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotl_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +* rotr_i32/i64 t0, t1, t2 + +Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64) + +********* Misc + +* mov_i32/i64 t0, t1 + +t0 = t1 + +Move t1 to t0 (both operands must have the same type). + +* ext8s_i32/i64 t0, t1 +ext8u_i32/i64 t0, t1 +ext16s_i32/i64 t0, t1 +ext16u_i32/i64 t0, t1 +ext32s_i64 t0, t1 +ext32u_i64 t0, t1 + +8, 16 or 32 bit sign/zero extension (both operands must have the same type) + +* bswap16_i32/i64 t0, t1 + +16 bit byte swap on a 32/64 bit value. The two/six high order bytes must be +set to zero. + +* bswap32_i32/i64 t0, t1 + +32 bit byte swap on a 32/64 bit value. With a 64 bit value, the four high +order bytes must be set to zero. + +* bswap64_i64 t0, t1 + +64 bit byte swap + +* discard_i32/i64 t0 + +Indicate that the value of t0 won't be used later. It is useful to +force dead code elimination. + +********* Type conversions + +* ext_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does sign extension + +* extu_i32_i64 t0, t1 +Convert t1 (32 bit) to t0 (64 bit) and does zero extension + +* trunc_i64_i32 t0, t1 +Truncate t1 (64 bit) to t0 (32 bit) + +* concat_i32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half +from t2 (32 bit). + +* concat32_i64 t0, t1, t2 +Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half +from t2 (64 bit). + +********* Load/Store + +* ld_i32/i64 t0, t1, offset +ld8s_i32/i64 t0, t1, offset +ld8u_i32/i64 t0, t1, offset +ld16s_i32/i64 t0, t1, offset +ld16u_i32/i64 t0, t1, offset +ld32s_i64 t0, t1, offset +ld32u_i64 t0, t1, offset + +t0 = read(t1 + offset) +Load 8, 16, 32 or 64 bits with or without sign extension from host memory. +offset must be a constant. + +* st_i32/i64 t0, t1, offset +st8_i32/i64 t0, t1, offset +st16_i32/i64 t0, t1, offset +st32_i64 t0, t1, offset + +write(t0, t1 + offset) +Write 8, 16, 32 or 64 bits to host memory. + +********* QEMU specific operations + +* tb_exit t0 + +Exit the current TB and return the value t0 (word type). + +* goto_tb index + +Exit the current TB and jump to the TB index 'index' (constant) if the +current TB was linked to this TB. Otherwise execute the next +instructions. + +* qemu_ld8u t0, t1, flags +qemu_ld8s t0, t1, flags +qemu_ld16u t0, t1, flags +qemu_ld16s t0, t1, flags +qemu_ld32u t0, t1, flags +qemu_ld32s t0, t1, flags +qemu_ld64 t0, t1, flags + +Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +* qemu_st8 t0, t1, flags +qemu_st16 t0, t1, flags +qemu_st32 t0, t1, flags +qemu_st64 t0, t1, flags + +Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU +address type. 'flags' contains the QEMU memory index (selects user or +kernel access) for example. + +Note 1: Some shortcuts are defined when the last operand is known to be +a constant (e.g. addi for add, movi for mov). + +Note 2: When using TCG, the opcodes must never be generated directly +as some of them may not be available as "real" opcodes. Always use the +function tcg_gen_xxx(args). + +4) Backend + +tcg-target.h contains the target specific definitions. tcg-target.c +contains the target specific code. + +4.1) Assumptions + +The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or +64 bit. It is expected that the pointer has the same size as the word. + +On a 32 bit target, all 64 bit operations are converted to 32 bits. A +few specific operations must be implemented to allow it (see add2_i32, +sub2_i32, brcond2_i32). + +Floating point operations are not supported in this version. A +previous incarnation of the code generator had full support of them, +but it is better to concentrate on integer operations first. + +On a 64 bit target, no assumption is made in TCG about the storage of +the 32 bit values in 64 bit registers. + +4.2) Constraints + +GCC like constraints are used to define the constraints of every +instruction. Memory constraints are not supported in this +version. Aliases are specified in the input operands as for GCC. + +The same register may be used for both an input and an output, even when +they are not explicitly aliased. If an op expands to multiple target +instructions then care must be taken to avoid clobbering input values. +GCC style "early clobber" outputs are not currently supported. + +A target can define specific register or constant constraints. If an +operation uses a constant input constraint which does not allow all +constants, it must also accept registers in order to have a fallback. + +The movi_i32 and movi_i64 operations must accept any constants. + +The mov_i32 and mov_i64 operations must accept any registers of the +same type. + +The ld/st instructions must accept signed 32 bit constant offsets. It +can be implemented by reserving a specific register to compute the +address if the offset is too big. + +The ld/st instructions must accept any destination (ld) or source (st) +register. + +4.3) Function call assumptions + +- The only supported types for parameters and return value are: 32 and + 64 bit integers and pointer. +- The stack grows downwards. +- The first N parameters are passed in registers. +- The next parameters are passed on the stack by storing them as words. +- Some registers are clobbered during the call. +- The function can return 0 or 1 value in registers. On a 32 bit + target, functions must be able to return 2 values in registers for + 64 bit return type. + +5) Recommended coding rules for best performance + +- Use globals to represent the parts of the QEMU CPU state which are + often modified, e.g. the integer registers and the condition + codes. TCG will be able to use host registers to store them. + +- Avoid globals stored in fixed registers. They must be used only to + store the pointer to the CPU state and possibly to store a pointer + to a register window. + +- Use temporaries. Use local temporaries only when really needed, + e.g. when you need to use a value after a jump. Local temporaries + introduce a performance hit in the current TCG implementation: their + content is saved to memory at end of each basic block. + +- Free temporaries and local temporaries when they are no longer used + (tcg_temp_free). Since tcg_const_x() also creates a temporary, you + should free it after it is used. Freeing temporaries does not yield + a better generated code, but it reduces the memory usage of TCG and + the speed of the translation. + +- Don't hesitate to use helpers for complicated or seldom used target + intructions. There is little performance advantage in using TCG to + implement target instructions taking more than about twenty TCG + instructions. + +- Use the 'discard' instruction if you know that TCG won't be able to + prove that a given global is "dead" at a given program point. The + x86 target uses it to improve the condition codes optimisation. diff --git a/qemu/qemu-git/tcg/TODO b/qemu/qemu-git/tcg/TODO new file mode 100644 index 0000000..f30cb75 --- /dev/null +++ b/qemu/qemu-git/tcg/TODO @@ -0,0 +1,14 @@ +- Add new instructions such as: setcond, clz, ctz, popcnt. + +- See if it is worth exporting mul2, mulu2, div2, divu2. + +- Support of globals saved in fixed registers between TBs. + +Ideas: + +- Move the slow part of the qemu_ld/st ops after the end of the TB. + +- Change exception syntax to get closer to QOP system (exception + parameters given with a specific instruction). + +- Add float and vector support. diff --git a/qemu/qemu-git/tcg/arm/.svn/all-wcprops b/qemu/qemu-git/tcg/arm/.svn/all-wcprops new file mode 100644 index 0000000..69b717b --- /dev/null +++ b/qemu/qemu-git/tcg/arm/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/arm +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/arm/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/arm/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/arm/.svn/entries b/qemu/qemu-git/tcg/arm/.svn/entries new file mode 100644 index 0000000..b18fb29 --- /dev/null +++ b/qemu/qemu-git/tcg/arm/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/arm +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +98deb0581c939945cb5a0611f98a6a5e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +54714 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +2f84ffc289d4ac8d17ea1350d0dcbc0e +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2650 + diff --git a/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..f8d626d --- /dev/null +++ b/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1708 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Andrzej Zaborowski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%r2", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 +}; +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R0, TCG_REG_R1 +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_ARM_ABS32: + *(uint32_t *) code_ptr = value; + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + default: + tcg_abort(); + + case R_ARM_PC24: + *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) | + (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff); + break; + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'I': + ct->ct |= TCG_CT_CONST_ARM; + break; + + case 'r': +#ifndef CONFIG_SOFTMMU + case 'd': + case 'D': + case 'x': + case 'X': +#endif + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + break; + +#ifdef CONFIG_SOFTMMU + /* qemu_ld/st inputs (unless 'X', 'd' or 'D') */ + case 'x': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld64 data_reg */ + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r1 is still needed to load data_reg2, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld/st64 data_reg2 */ + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0, r1 and optionally r2 will be overwritten by the address + * and the low word of data, so don't use these. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); +# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); +# endif + break; + +# if TARGET_LONG_BITS == 64 + /* qemu_ld/st addr_reg2 */ + case 'X': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0 will be overwritten by the low word of base, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; +# endif +#endif + + case '1': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + break; + + case '2': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + + return 0; +} + +static inline uint32_t rotl(uint32_t val, int n) +{ + return (val << n) | (val >> (32 - n)); +} + +/* ARM immediates for ALU instructions are made of an unsigned 8-bit + right-rotated by an even amount between 0 and 30. */ +static inline int encode_imm(uint32_t imm) +{ + int shift; + + /* simple case, only lower bits */ + if ((imm & ~0xff) == 0) + return 0; + /* then try a simple even shift */ + shift = ctz32(imm) & ~1; + if (((imm >> shift) & ~0xff) == 0) + return 32 - shift; + /* now try harder with rotations */ + if ((rotl(imm, 2) & ~0xff) == 0) + return 2; + if ((rotl(imm, 4) & ~0xff) == 0) + return 4; + if ((rotl(imm, 6) & ~0xff) == 0) + return 6; + /* imm can't be encoded */ + return -1; +} + +static inline int check_fit_imm(uint32_t imm) +{ + return encode_imm(imm) >= 0; +} + +/* Test if a constant matches the constraint. + * TODO: define constraints for: + * + * ldr/str offset: between -0xfff and 0xfff + * ldrh/strh offset: between -0xff and 0xff + * mov operand2: values represented with x << (2 * y), x < 0x100 + * add, sub, eor...: ditto + */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val)) + return 1; + else + return 0; +} + +enum arm_data_opc_e { + ARITH_AND = 0x0, + ARITH_EOR = 0x1, + ARITH_SUB = 0x2, + ARITH_RSB = 0x3, + ARITH_ADD = 0x4, + ARITH_ADC = 0x5, + ARITH_SBC = 0x6, + ARITH_RSC = 0x7, + ARITH_TST = 0x8, + ARITH_CMP = 0xa, + ARITH_CMN = 0xb, + ARITH_ORR = 0xc, + ARITH_MOV = 0xd, + ARITH_BIC = 0xe, + ARITH_MVN = 0xf, +}; + +#define TO_CPSR(opc) \ + ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20) + +#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) +#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20) +#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40) +#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60) +#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10) +#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30) +#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50) +#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70) + +enum arm_cond_code_e { + COND_EQ = 0x0, + COND_NE = 0x1, + COND_CS = 0x2, /* Unsigned greater or equal */ + COND_CC = 0x3, /* Unsigned less than */ + COND_MI = 0x4, /* Negative */ + COND_PL = 0x5, /* Zero or greater */ + COND_VS = 0x6, /* Overflow */ + COND_VC = 0x7, /* No overflow */ + COND_HI = 0x8, /* Unsigned greater than */ + COND_LS = 0x9, /* Unsigned less or equal */ + COND_GE = 0xa, + COND_LT = 0xb, + COND_GT = 0xc, + COND_LE = 0xd, + COND_AL = 0xe, +}; + +static const uint8_t tcg_cond_to_arm_cond[10] = { + [TCG_COND_EQ] = COND_EQ, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_LT, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_GT, + /* unsigned */ + [TCG_COND_LTU] = COND_CC, + [TCG_COND_GEU] = COND_CS, + [TCG_COND_LEU] = COND_LS, + [TCG_COND_GTU] = COND_HI, +}; + +static inline void tcg_out_bx(TCGContext *s, int cond, int rn) +{ + tcg_out32(s, (cond << 28) | 0x012fff10 | rn); +} + +static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0a000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_b_noaddr(TCGContext *s, int cond) +{ +#ifdef HOST_WORDS_BIGENDIAN + tcg_out8(s, (cond << 4) | 0x0a); + s->code_ptr += 3; +#else + s->code_ptr += 3; + tcg_out8(s, (cond << 4) | 0x0a); +#endif +} + +static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0b000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_dat_reg(TCGContext *s, + int cond, int opc, int rd, int rn, int rm, int shift) +{ + tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | shift | rm); +} + +static inline void tcg_out_dat_reg2(TCGContext *s, + int cond, int opc0, int opc1, int rd0, int rd1, + int rn0, int rn1, int rm0, int rm1, int shift) +{ + if (rd0 == rn1 || rd0 == rm1) { + tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | + (rn0 << 16) | (8 << 12) | shift | rm0); + tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | + (rn1 << 16) | (rd1 << 12) | shift | rm1); + tcg_out_dat_reg(s, cond, ARITH_MOV, + rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); + } else { + tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | + (rn0 << 16) | (rd0 << 12) | shift | rm0); + tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | + (rn1 << 16) | (rd1 << 12) | shift | rm1); + } +} + +static inline void tcg_out_dat_imm(TCGContext *s, + int cond, int opc, int rd, int rn, int im) +{ + tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | im); +} + +static inline void tcg_out_movi32(TCGContext *s, + int cond, int rd, int32_t arg) +{ + int offset = (uint32_t) arg - ((uint32_t) s->code_ptr + 8); + + /* TODO: This is very suboptimal, we can easily have a constant + * pool somewhere after all the instructions. */ + + if (arg < 0 && arg > -0x100) + return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); + + if (offset < 0x100 && offset > -0x100) + return offset >= 0 ? + tcg_out_dat_imm(s, cond, ARITH_ADD, rd, 15, offset) : + tcg_out_dat_imm(s, cond, ARITH_SUB, rd, 15, -offset); + +#ifdef __ARM_ARCH_7A__ + /* use movw/movt */ + /* movw */ + tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12) + | ((arg << 4) & 0x000f0000) | (arg & 0xfff)); + if (arg & 0xffff0000) + /* movt */ + tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12) + | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff)); +#else + tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff); + if (arg & 0x0000ff00) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 8) & 0xff) | 0xc00); + if (arg & 0x00ff0000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 16) & 0xff) | 0x800); + if (arg & 0xff000000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 24) & 0xff) | 0x400); +#endif +} + +static inline void tcg_out_mul32(TCGContext *s, + int cond, int rd, int rs, int rm) +{ + if (rd != rm) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + else if (rd != rs) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rm << 8) | 0x90 | rs); + else { + tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + tcg_out_dat_reg(s, cond, ARITH_MOV, + rd, 0, 8, SHIFT_IMM_LSL(0)); + } +} + +static inline void tcg_out_umull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0x800098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_smull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0xc00098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_ld32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05900000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05100000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05800000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05000000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07900000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07800000 | + (rn << 16) | (rd << 12) | rm); +} + +/* Register pre-increment with base writeback. */ +static inline void tcg_out_ld32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07b00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07a00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05d00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05500000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05c00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05400000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07d00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07c00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld32u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st32(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + + val = addr - (tcg_target_long) s->code_ptr; + if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd) + tcg_out_b(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R8, val - 8); + tcg_out_dat_reg(s, cond, ARITH_ADD, + 15, 15, TCG_REG_R8, SHIFT_IMM_LSL(0)); + } +#endif + } +} + +static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + + val = addr - (tcg_target_long) s->code_ptr; + if (val < 0x01fffffd && val > -0x01fffffd) + tcg_out_bl(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_dat_imm(s, cond, ARITH_ADD, 14, 15, 4); + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R9, addr); + tcg_out_dat_imm(s, cond, ARITH_MOV, 14, 0, 15); + tcg_out_bx(s, cond, TCG_REG_R9); + } +#endif + } + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_callr(TCGContext *s, int cond, int arg) +{ +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + /* TODO: on ARMv5 and ARMv6 replace with tcg_out_blx(s, cond, arg); */ + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 15, SHIFT_IMM_LSL(0)); + tcg_out_bx(s, cond, arg); +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out_goto(s, cond, l->u.value); + else if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337); + s->code_ptr += 4; + } else { + /* Probably this should be preferred even for COND_AL... */ + tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337); + tcg_out_b_noaddr(s, cond); + } +} + +static void tcg_out_div_helper(TCGContext *s, int cond, const TCGArg *args, + void *helper_div, void *helper_rem, int shift) +{ + int div_reg = args[0]; + int rem_reg = args[1]; + + /* stmdb sp!, { r0 - r3, ip, lr } */ + /* (Note that we need an even number of registers as per EABI) */ + tcg_out32(s, (cond << 28) | 0x092d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_div); + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 0, SHIFT_IMM_LSL(0)); + + /* ldmia sp, { r0 - r3, fp, lr } */ + tcg_out32(s, (cond << 28) | 0x089d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_rem); + + tcg_out_dat_reg(s, cond, ARITH_MOV, rem_reg, 0, 0, SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, div_reg, 0, 8, SHIFT_IMM_LSL(0)); + + /* ldr r0, [sp], #4 */ + if (rem_reg != 0 && div_reg != 0) + tcg_out32(s, (cond << 28) | 0x04bd0004); + /* ldr r1, [sp], #4 */ + if (rem_reg != 1 && div_reg != 1) + tcg_out32(s, (cond << 28) | 0x04bd1004); + /* ldr r2, [sp], #4 */ + if (rem_reg != 2 && div_reg != 2) + tcg_out32(s, (cond << 28) | 0x04bd2004); + /* ldr r3, [sp], #4 */ + if (rem_reg != 3 && div_reg != 3) + tcg_out32(s, (cond << 28) | 0x04bd3004); + /* ldr ip, [sp], #4 */ + if (rem_reg != 12 && div_reg != 12) + tcg_out32(s, (cond << 28) | 0x04bdc004); + /* ldr lr, [sp], #4 */ + if (rem_reg != 14 && div_reg != 14) + tcg_out32(s, (cond << 28) | 0x04bde004); +} + +#ifdef CONFIG_SOFTMMU + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) + +static inline void tcg_out_qemu_ld(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#ifdef CONFIG_SOFTMMU +# if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +# endif + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ +# if CPU_TLB_BITS > 8 +# error +# endif + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read) + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_ld32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_ld32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + tcg_out_dat_imm(s, cond, ARITH_MOV, 1, 0, mem_index); +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); +# endif + tcg_out_bl(s, cond, (tcg_target_long) qemu_ld_helpers[s_bits] - + (tcg_target_long) s->code_ptr); + + switch (opc) { + case 0 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(24)); + break; + case 1 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(16)); + break; + case 0: + case 1: + case 2: + default: + if (data_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + break; + case 3: + if (data_reg != 0) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + if (data_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg2, 0, 1, SHIFT_IMM_LSL(0)); + break; + } + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } + switch (opc) { + case 0: + tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block load - + * check that data_reg2 > data_reg or the other way */ + if (data_reg == addr_reg) { + tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + } else { + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); + } + break; + } +#endif +} + +static inline void tcg_out_qemu_st(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#ifdef CONFIG_SOFTMMU +# if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +# endif + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write) + + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, 1, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 2: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 3: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + } +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, 2, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 2: + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 3: + tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index); + tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */ + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 3) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 3, 0, data_reg2, SHIFT_IMM_LSL(0)); + break; + } +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] - + (tcg_target_long) s->code_ptr); +# if TARGET_LONG_BITS == 64 + if (opc == 3) + tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10); +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } + switch (opc) { + case 0: + tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block store - + * check that data_reg2 > data_reg or the other way */ + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4); + break; + } +#endif +} + +static uint8_t *tb_ret_addr; + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: +#ifdef SAVE_LR + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0)); + if (args[0] >> 8) + tcg_out32(s, args[0]); +#else + { + uint8_t *ld_ptr = s->code_ptr; + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, 0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); + tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); + if (args[0] >> 8) { + *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8; + tcg_out32(s, args[0]); + } + } +#endif + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* Direct jump method */ +#if defined(USE_DIRECT_JUMP) + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out_b(s, COND_AL, 8); +#else + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); +#endif + } else { + /* Indirect jump method */ +#if 1 + c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8); + if (c > 0xfff || c < -0xfff) { + tcg_out_movi32(s, COND_AL, TCG_REG_R0, + (tcg_target_long) (s->tb_next + args[0])); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + } else + tcg_out_ld32_12(s, COND_AL, 15, 15, c); +#else + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + tcg_out32(s, (tcg_target_long) (s->tb_next + args[0])); +#endif + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out_call(s, COND_AL, args[0]); + else + tcg_out_callr(s, COND_AL, args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) + tcg_out_goto(s, COND_AL, args[0]); + else + tcg_out_bx(s, COND_AL, args[0]); + break; + case INDEX_op_br: + tcg_out_goto_label(s, COND_AL, args[0]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); + break; + + case INDEX_op_mov_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_movi_i32: + tcg_out_movi32(s, COND_AL, args[0], args[1]); + break; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_ORR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_EOR; + /* Fall through. */ + gen_arith: + if (const_args[2]) { + int rot; + rot = encode_imm(args[2]); + tcg_out_dat_imm(s, COND_AL, c, + args[0], args[1], rotl(args[2], rot) | (rot << 7)); + } else + tcg_out_dat_reg(s, COND_AL, c, + args[0], args[1], args[2], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_add2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_sub2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_neg_i32: + tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); + break; + case INDEX_op_not_i32: + tcg_out_dat_reg(s, COND_AL, + ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_mul_i32: + tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_mulu2_i32: + tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_div_i64, tcg_helper_rem_i64, + SHIFT_IMM_ASR(31)); + break; + case INDEX_op_divu2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_divu_i64, tcg_helper_remu_i64, + SHIFT_IMM_LSR(31)); + break; + /* XXX: Perhaps args[2] & 0x1f is wrong */ + case INDEX_op_shl_i32: + c = const_args[2] ? + SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); + goto gen_shift32; + case INDEX_op_shr_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); + goto gen_shift32; + case INDEX_op_sar_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); + /* Fall through. */ + gen_shift32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); + break; + + case INDEX_op_brcond_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[0], args[1], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); + break; + case INDEX_op_brcond2_i32: + /* The resulting conditions are: + * TCG_COND_EQ --> a0 == a2 && a1 == a3, + * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3, + * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3, + * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3), + * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3), + * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3, + */ + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[1], args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, + args[0], args[2], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, COND_AL, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, COND_AL, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, COND_AL, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, COND_AL, args, 3); + break; + + case INDEX_op_ext8s_i32: +#ifdef __ARM_ARCH_7A__ + /* sxtb */ + tcg_out32(s, 0xe6af0070 | (args[0] << 12) | args[1]); +#else + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(24)); +#endif + break; + case INDEX_op_ext16s_i32: +#ifdef __ARM_ARCH_7A__ + /* sxth */ + tcg_out32(s, 0xe6bf0070 | (args[0] << 12) | args[1]); +#else + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(16)); +#endif + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef arm_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + /* TODO: "r", "r", "ri" */ + { INDEX_op_add_i32, { "r", "r", "rI" } }, + { INDEX_op_sub_i32, { "r", "r", "rI" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_and_i32, { "r", "r", "rI" } }, + { INDEX_op_or_i32, { "r", "r", "rI" } }, + { INDEX_op_xor_i32, { "r", "r", "rI" } }, + { INDEX_op_neg_i32, { "r", "r" } }, + { INDEX_op_not_i32, { "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + + /* TODO: "r", "r", "r", "r", "ri", "ri" */ + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld8s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld32u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } }, + + { INDEX_op_qemu_st8, { "x", "x", "X" } }, + { INDEX_op_qemu_st16, { "x", "x", "X" } }, + { INDEX_op_qemu_st32, { "x", "x", "X" } }, + { INDEX_op_qemu_st64, { "x", "D", "x", "X" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, + ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8)); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + ((2 << TCG_REG_R3) - 1) | + (1 << TCG_REG_R12) | (1 << TCG_REG_R14)); + + tcg_regset_clear(s->reserved_regs); +#ifdef SAVE_LR + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8); + + tcg_add_target_add_op_defs(arm_op_defs); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ld32u(s, COND_AL, arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_st32(s, COND_AL, arg, arg1, arg2); +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val > 0) + if (val < 0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val); + else + tcg_abort(); + else if (val < 0) { + if (val > -0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val); + else + tcg_abort(); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0)); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_out_movi32(s, COND_AL, ret, arg); +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + /* stmdb sp!, { r9 - r11, lr } */ + tcg_out32(s, (COND_AL << 28) | 0x092d4e00); + + tcg_out_bx(s, COND_AL, TCG_REG_R0); + tb_ret_addr = s->code_ptr; + + /* ldmia sp!, { r9 - r11, pc } */ + tcg_out32(s, (COND_AL << 28) | 0x08bd8e00); +} diff --git a/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..71e1ec5 --- /dev/null +++ b/qemu/qemu-git/tcg/arm/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,85 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * Copyright (c) 2008 Andrzej Zaborowski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_ARM 1 + +#define TCG_TARGET_REG_BITS 32 +#undef TCG_TARGET_WORDS_BIGENDIAN +#undef TCG_TARGET_HAS_div_i32 +#undef TCG_TARGET_HAS_div_i64 +#undef TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_neg_i32 +#undef TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_not_i32 +#undef TCG_TARGET_STACK_GROWSUP + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, +}; + +#define TCG_TARGET_NB_REGS 15 + +#define TCG_CT_CONST_ARM 0x100 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R13 +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +#define TCG_TARGET_HAS_GUEST_BASE + +enum { + /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R7, + TCG_AREG1 = TCG_REG_R4, + TCG_AREG2 = TCG_REG_R5, +}; + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +#if QEMU_GNUC_PREREQ(4, 1) + __builtin___clear_cache((char *) start, (char *) stop); +#else + register unsigned long _beg __asm ("a1") = start; + register unsigned long _end __asm ("a2") = stop; + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +#endif +} diff --git a/qemu/qemu-git/tcg/arm/tcg-target.c b/qemu/qemu-git/tcg/arm/tcg-target.c new file mode 100644 index 0000000..f8d626d --- /dev/null +++ b/qemu/qemu-git/tcg/arm/tcg-target.c @@ -0,0 +1,1708 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Andrzej Zaborowski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%r2", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 +}; +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R0, TCG_REG_R1 +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_ARM_ABS32: + *(uint32_t *) code_ptr = value; + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + default: + tcg_abort(); + + case R_ARM_PC24: + *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) | + (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff); + break; + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'I': + ct->ct |= TCG_CT_CONST_ARM; + break; + + case 'r': +#ifndef CONFIG_SOFTMMU + case 'd': + case 'D': + case 'x': + case 'X': +#endif + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + break; + +#ifdef CONFIG_SOFTMMU + /* qemu_ld/st inputs (unless 'X', 'd' or 'D') */ + case 'x': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld64 data_reg */ + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r1 is still needed to load data_reg2, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + /* qemu_ld/st64 data_reg2 */ + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0, r1 and optionally r2 will be overwritten by the address + * and the low word of data, so don't use these. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); +# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); +# endif + break; + +# if TARGET_LONG_BITS == 64 + /* qemu_ld/st addr_reg2 */ + case 'X': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + /* r0 will be overwritten by the low word of base, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; +# endif +#endif + + case '1': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + break; + + case '2': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); + break; + + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + + return 0; +} + +static inline uint32_t rotl(uint32_t val, int n) +{ + return (val << n) | (val >> (32 - n)); +} + +/* ARM immediates for ALU instructions are made of an unsigned 8-bit + right-rotated by an even amount between 0 and 30. */ +static inline int encode_imm(uint32_t imm) +{ + int shift; + + /* simple case, only lower bits */ + if ((imm & ~0xff) == 0) + return 0; + /* then try a simple even shift */ + shift = ctz32(imm) & ~1; + if (((imm >> shift) & ~0xff) == 0) + return 32 - shift; + /* now try harder with rotations */ + if ((rotl(imm, 2) & ~0xff) == 0) + return 2; + if ((rotl(imm, 4) & ~0xff) == 0) + return 4; + if ((rotl(imm, 6) & ~0xff) == 0) + return 6; + /* imm can't be encoded */ + return -1; +} + +static inline int check_fit_imm(uint32_t imm) +{ + return encode_imm(imm) >= 0; +} + +/* Test if a constant matches the constraint. + * TODO: define constraints for: + * + * ldr/str offset: between -0xfff and 0xfff + * ldrh/strh offset: between -0xff and 0xff + * mov operand2: values represented with x << (2 * y), x < 0x100 + * add, sub, eor...: ditto + */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val)) + return 1; + else + return 0; +} + +enum arm_data_opc_e { + ARITH_AND = 0x0, + ARITH_EOR = 0x1, + ARITH_SUB = 0x2, + ARITH_RSB = 0x3, + ARITH_ADD = 0x4, + ARITH_ADC = 0x5, + ARITH_SBC = 0x6, + ARITH_RSC = 0x7, + ARITH_TST = 0x8, + ARITH_CMP = 0xa, + ARITH_CMN = 0xb, + ARITH_ORR = 0xc, + ARITH_MOV = 0xd, + ARITH_BIC = 0xe, + ARITH_MVN = 0xf, +}; + +#define TO_CPSR(opc) \ + ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20) + +#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) +#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20) +#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40) +#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60) +#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10) +#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30) +#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50) +#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70) + +enum arm_cond_code_e { + COND_EQ = 0x0, + COND_NE = 0x1, + COND_CS = 0x2, /* Unsigned greater or equal */ + COND_CC = 0x3, /* Unsigned less than */ + COND_MI = 0x4, /* Negative */ + COND_PL = 0x5, /* Zero or greater */ + COND_VS = 0x6, /* Overflow */ + COND_VC = 0x7, /* No overflow */ + COND_HI = 0x8, /* Unsigned greater than */ + COND_LS = 0x9, /* Unsigned less or equal */ + COND_GE = 0xa, + COND_LT = 0xb, + COND_GT = 0xc, + COND_LE = 0xd, + COND_AL = 0xe, +}; + +static const uint8_t tcg_cond_to_arm_cond[10] = { + [TCG_COND_EQ] = COND_EQ, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_LT, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_GT, + /* unsigned */ + [TCG_COND_LTU] = COND_CC, + [TCG_COND_GEU] = COND_CS, + [TCG_COND_LEU] = COND_LS, + [TCG_COND_GTU] = COND_HI, +}; + +static inline void tcg_out_bx(TCGContext *s, int cond, int rn) +{ + tcg_out32(s, (cond << 28) | 0x012fff10 | rn); +} + +static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0a000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_b_noaddr(TCGContext *s, int cond) +{ +#ifdef HOST_WORDS_BIGENDIAN + tcg_out8(s, (cond << 4) | 0x0a); + s->code_ptr += 3; +#else + s->code_ptr += 3; + tcg_out8(s, (cond << 4) | 0x0a); +#endif +} + +static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset) +{ + tcg_out32(s, (cond << 28) | 0x0b000000 | + (((offset - 8) >> 2) & 0x00ffffff)); +} + +static inline void tcg_out_dat_reg(TCGContext *s, + int cond, int opc, int rd, int rn, int rm, int shift) +{ + tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | shift | rm); +} + +static inline void tcg_out_dat_reg2(TCGContext *s, + int cond, int opc0, int opc1, int rd0, int rd1, + int rn0, int rn1, int rm0, int rm1, int shift) +{ + if (rd0 == rn1 || rd0 == rm1) { + tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | + (rn0 << 16) | (8 << 12) | shift | rm0); + tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | + (rn1 << 16) | (rd1 << 12) | shift | rm1); + tcg_out_dat_reg(s, cond, ARITH_MOV, + rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); + } else { + tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | + (rn0 << 16) | (rd0 << 12) | shift | rm0); + tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | + (rn1 << 16) | (rd1 << 12) | shift | rm1); + } +} + +static inline void tcg_out_dat_imm(TCGContext *s, + int cond, int opc, int rd, int rn, int im) +{ + tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) | + (rn << 16) | (rd << 12) | im); +} + +static inline void tcg_out_movi32(TCGContext *s, + int cond, int rd, int32_t arg) +{ + int offset = (uint32_t) arg - ((uint32_t) s->code_ptr + 8); + + /* TODO: This is very suboptimal, we can easily have a constant + * pool somewhere after all the instructions. */ + + if (arg < 0 && arg > -0x100) + return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); + + if (offset < 0x100 && offset > -0x100) + return offset >= 0 ? + tcg_out_dat_imm(s, cond, ARITH_ADD, rd, 15, offset) : + tcg_out_dat_imm(s, cond, ARITH_SUB, rd, 15, -offset); + +#ifdef __ARM_ARCH_7A__ + /* use movw/movt */ + /* movw */ + tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12) + | ((arg << 4) & 0x000f0000) | (arg & 0xfff)); + if (arg & 0xffff0000) + /* movt */ + tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12) + | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff)); +#else + tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff); + if (arg & 0x0000ff00) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 8) & 0xff) | 0xc00); + if (arg & 0x00ff0000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 16) & 0xff) | 0x800); + if (arg & 0xff000000) + tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, + ((arg >> 24) & 0xff) | 0x400); +#endif +} + +static inline void tcg_out_mul32(TCGContext *s, + int cond, int rd, int rs, int rm) +{ + if (rd != rm) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + else if (rd != rs) + tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | + (rm << 8) | 0x90 | rs); + else { + tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) | + (rs << 8) | 0x90 | rm); + tcg_out_dat_reg(s, cond, ARITH_MOV, + rd, 0, 8, SHIFT_IMM_LSL(0)); + } +} + +static inline void tcg_out_umull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0x800090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0x800098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_smull32(TCGContext *s, + int cond, int rd0, int rd1, int rs, int rm) +{ + if (rd0 != rm && rd1 != rm) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); + else if (rd0 != rs && rd1 != rs) + tcg_out32(s, (cond << 28) | 0xc00090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); + else { + tcg_out_dat_reg(s, cond, ARITH_MOV, + TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); + tcg_out32(s, (cond << 28) | 0xc00098 | + (rd1 << 16) | (rd0 << 12) | (rs << 8)); + } +} + +static inline void tcg_out_ld32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05900000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05100000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st32_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05800000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05000000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07900000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07800000 | + (rn << 16) | (rd << 12) | rm); +} + +/* Register pre-increment with base writeback. */ +static inline void tcg_out_ld32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07b00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st32_rwb(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07a00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16u_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000b0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000b0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16u_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000b0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st16s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000f0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000f0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st16s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000f0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05d00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05500000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_st8_12(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x05c00000 | + (rn << 16) | (rd << 12) | (im & 0xfff)); + else + tcg_out32(s, (cond << 28) | 0x05400000 | + (rn << 16) | (rd << 12) | ((-im) & 0xfff)); +} + +static inline void tcg_out_ld8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07d00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x07c00000 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01d000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x015000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_st8s_8(TCGContext *s, int cond, + int rd, int rn, tcg_target_long im) +{ + if (im >= 0) + tcg_out32(s, (cond << 28) | 0x01c000d0 | + (rn << 16) | (rd << 12) | + ((im & 0xf0) << 4) | (im & 0xf)); + else + tcg_out32(s, (cond << 28) | 0x014000d0 | + (rn << 16) | (rd << 12) | + (((-im) & 0xf0) << 4) | ((-im) & 0xf)); +} + +static inline void tcg_out_ld8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x019000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_st8s_r(TCGContext *s, int cond, + int rd, int rn, int rm) +{ + tcg_out32(s, (cond << 28) | 0x018000d0 | + (rn << 16) | (rd << 12) | rm); +} + +static inline void tcg_out_ld32u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st32(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st32_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld16s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld16s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st16u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st16u_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st16u_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_ld8s(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_ld8s_8(s, cond, rd, rn, offset); +} + +static inline void tcg_out_st8u(TCGContext *s, int cond, + int rd, int rn, int32_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, cond, TCG_REG_R8, offset); + tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8); + } else + tcg_out_st8_12(s, cond, rd, rn, offset); +} + +static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + + val = addr - (tcg_target_long) s->code_ptr; + if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd) + tcg_out_b(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R8, val - 8); + tcg_out_dat_reg(s, cond, ARITH_ADD, + 15, 15, TCG_REG_R8, SHIFT_IMM_LSL(0)); + } +#endif + } +} + +static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr) +{ + int32_t val; + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + + val = addr - (tcg_target_long) s->code_ptr; + if (val < 0x01fffffd && val > -0x01fffffd) + tcg_out_bl(s, cond, val); + else { +#if 1 + tcg_abort(); +#else + if (cond == COND_AL) { + tcg_out_dat_imm(s, cond, ARITH_ADD, 14, 15, 4); + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ + } else { + tcg_out_movi32(s, cond, TCG_REG_R9, addr); + tcg_out_dat_imm(s, cond, ARITH_MOV, 14, 0, 15); + tcg_out_bx(s, cond, TCG_REG_R9); + } +#endif + } + +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_callr(TCGContext *s, int cond, int arg) +{ +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); +#endif + /* TODO: on ARMv5 and ARMv6 replace with tcg_out_blx(s, cond, arg); */ + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 15, SHIFT_IMM_LSL(0)); + tcg_out_bx(s, cond, arg); +#ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); +#endif +} + +static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out_goto(s, cond, l->u.value); + else if (cond == COND_AL) { + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337); + s->code_ptr += 4; + } else { + /* Probably this should be preferred even for COND_AL... */ + tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337); + tcg_out_b_noaddr(s, cond); + } +} + +static void tcg_out_div_helper(TCGContext *s, int cond, const TCGArg *args, + void *helper_div, void *helper_rem, int shift) +{ + int div_reg = args[0]; + int rem_reg = args[1]; + + /* stmdb sp!, { r0 - r3, ip, lr } */ + /* (Note that we need an even number of registers as per EABI) */ + tcg_out32(s, (cond << 28) | 0x092d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_div); + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 0, SHIFT_IMM_LSL(0)); + + /* ldmia sp, { r0 - r3, fp, lr } */ + tcg_out32(s, (cond << 28) | 0x089d500f); + + tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); + + tcg_out_call(s, cond, (uint32_t) helper_rem); + + tcg_out_dat_reg(s, cond, ARITH_MOV, rem_reg, 0, 0, SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, cond, ARITH_MOV, div_reg, 0, 8, SHIFT_IMM_LSL(0)); + + /* ldr r0, [sp], #4 */ + if (rem_reg != 0 && div_reg != 0) + tcg_out32(s, (cond << 28) | 0x04bd0004); + /* ldr r1, [sp], #4 */ + if (rem_reg != 1 && div_reg != 1) + tcg_out32(s, (cond << 28) | 0x04bd1004); + /* ldr r2, [sp], #4 */ + if (rem_reg != 2 && div_reg != 2) + tcg_out32(s, (cond << 28) | 0x04bd2004); + /* ldr r3, [sp], #4 */ + if (rem_reg != 3 && div_reg != 3) + tcg_out32(s, (cond << 28) | 0x04bd3004); + /* ldr ip, [sp], #4 */ + if (rem_reg != 12 && div_reg != 12) + tcg_out32(s, (cond << 28) | 0x04bdc004); + /* ldr lr, [sp], #4 */ + if (rem_reg != 14 && div_reg != 14) + tcg_out32(s, (cond << 28) | 0x04bde004); +} + +#ifdef CONFIG_SOFTMMU + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) + +static inline void tcg_out_qemu_ld(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#ifdef CONFIG_SOFTMMU +# if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +# endif + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ +# if CPU_TLB_BITS > 8 +# error +# endif + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_read) + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_ld32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_ld32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + tcg_out_dat_imm(s, cond, ARITH_MOV, 1, 0, mem_index); +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); +# endif + tcg_out_bl(s, cond, (tcg_target_long) qemu_ld_helpers[s_bits] - + (tcg_target_long) s->code_ptr); + + switch (opc) { + case 0 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(24)); + break; + case 1 | 4: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, 0, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_ASR(16)); + break; + case 0: + case 1: + case 2: + default: + if (data_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + break; + case 3: + if (data_reg != 0) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg, 0, 0, SHIFT_IMM_LSL(0)); + if (data_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + data_reg2, 0, 1, SHIFT_IMM_LSL(0)); + break; + } + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } + switch (opc) { + case 0: + tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block load - + * check that data_reg2 > data_reg or the other way */ + if (data_reg == addr_reg) { + tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + } else { + tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); + } + break; + } +#endif +} + +static inline void tcg_out_qemu_st(TCGContext *s, int cond, + const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +# if TARGET_LONG_BITS == 64 + int addr_reg2; +# endif + uint32_t *label_ptr; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#ifdef CONFIG_SOFTMMU +# if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +# endif + mem_index = *args; + s_bits = opc & 3; + + /* Should generate something like the following: + * shr r8, addr_reg, #TARGET_PAGE_BITS + * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 + * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS + */ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); + tcg_out_dat_imm(s, COND_AL, ARITH_AND, + 0, 8, CPU_TLB_SIZE - 1); + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, + 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); + /* In the + * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))] + * below, the offset is likely to exceed 12 bits if mem_index != 0 and + * not exceed otherwise, so use an + * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) + * before. + */ + if (mem_index) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, + (mem_index << (TLB_SHIFT & 1)) | + ((16 - (TLB_SHIFT >> 1)) << 8)); + tcg_out_ld32_12(s, COND_AL, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write)); + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, + 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); + /* Check alignment. */ + if (s_bits) + tcg_out_dat_imm(s, COND_EQ, ARITH_TST, + 0, addr_reg, (1 << s_bits) - 1); +# if TARGET_LONG_BITS == 64 + /* XXX: possibly we could use a block data load or writeback in + * the first access. */ + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addr_write) + + 4); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, + 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); +# endif + tcg_out_ld32_12(s, COND_EQ, 1, 0, + offsetof(CPUState, tlb_table[0][0].addend)); + + switch (opc) { + case 0: + tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 0 | 4: + tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1: + tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 1 | 4: + tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 2: + default: + tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1); + break; + case 3: + tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg); + tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4); + break; + } + + label_ptr = (void *) s->code_ptr; + tcg_out_b(s, COND_EQ, 8); + + /* TODO: move this code to where the constants pool will be */ + if (addr_reg) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 0, 0, addr_reg, SHIFT_IMM_LSL(0)); +# if TARGET_LONG_BITS == 32 + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, 1, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 2: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); + break; + case 3: + if (data_reg != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg2, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + } +# else + if (addr_reg2 != 1) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); + switch (opc) { + case 0: + tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 1: + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, 2, SHIFT_IMM_LSR(16)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 2: + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); + break; + case 3: + tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index); + tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */ + if (data_reg != 2) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 2, 0, data_reg, SHIFT_IMM_LSL(0)); + if (data_reg2 != 3) + tcg_out_dat_reg(s, cond, ARITH_MOV, + 3, 0, data_reg2, SHIFT_IMM_LSL(0)); + break; + } +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); +# endif + + tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] - + (tcg_target_long) s->code_ptr); +# if TARGET_LONG_BITS == 64 + if (opc == 3) + tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10); +# endif + +# ifdef SAVE_LR + tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); +# endif + + *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; +#else /* !CONFIG_SOFTMMU */ + if (GUEST_BASE) { + uint32_t offset = GUEST_BASE; + int i; + int rot; + + while (offset) { + i = ctz32(offset) & ~1; + rot = ((32 - i) << 7) & 0xf00; + + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, + ((offset >> i) & 0xff) | rot); + addr_reg = 8; + offset &= ~(0xff << i); + } + } + switch (opc) { + case 0: + tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 0 | 4: + tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1: + tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 1 | 4: + tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0); + break; + case 2: + default: + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + break; + case 3: + /* TODO: use block store - + * check that data_reg2 > data_reg or the other way */ + tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); + tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4); + break; + } +#endif +} + +static uint8_t *tb_ret_addr; + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: +#ifdef SAVE_LR + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0)); + if (args[0] >> 8) + tcg_out32(s, args[0]); +#else + { + uint8_t *ld_ptr = s->code_ptr; + if (args[0] >> 8) + tcg_out_ld32_12(s, COND_AL, 0, 15, 0); + else + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); + tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); + if (args[0] >> 8) { + *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8; + tcg_out32(s, args[0]); + } + } +#endif + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* Direct jump method */ +#if defined(USE_DIRECT_JUMP) + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out_b(s, COND_AL, 8); +#else + tcg_out_ld32_12(s, COND_AL, 15, 15, -4); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); +#endif + } else { + /* Indirect jump method */ +#if 1 + c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8); + if (c > 0xfff || c < -0xfff) { + tcg_out_movi32(s, COND_AL, TCG_REG_R0, + (tcg_target_long) (s->tb_next + args[0])); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + } else + tcg_out_ld32_12(s, COND_AL, 15, 15, c); +#else + tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); + tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); + tcg_out32(s, (tcg_target_long) (s->tb_next + args[0])); +#endif + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out_call(s, COND_AL, args[0]); + else + tcg_out_callr(s, COND_AL, args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) + tcg_out_goto(s, COND_AL, args[0]); + else + tcg_out_bx(s, COND_AL, args[0]); + break; + case INDEX_op_br: + tcg_out_goto_label(s, COND_AL, args[0]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); + break; + + case INDEX_op_mov_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_movi_i32: + tcg_out_movi32(s, COND_AL, args[0], args[1]); + break; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_ORR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_EOR; + /* Fall through. */ + gen_arith: + if (const_args[2]) { + int rot; + rot = encode_imm(args[2]); + tcg_out_dat_imm(s, COND_AL, c, + args[0], args[1], rotl(args[2], rot) | (rot << 7)); + } else + tcg_out_dat_reg(s, COND_AL, c, + args[0], args[1], args[2], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_add2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_sub2_i32: + tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC, + args[0], args[1], args[2], args[3], + args[4], args[5], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_neg_i32: + tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); + break; + case INDEX_op_not_i32: + tcg_out_dat_reg(s, COND_AL, + ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0)); + break; + case INDEX_op_mul_i32: + tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); + break; + case INDEX_op_mulu2_i32: + tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_div_i64, tcg_helper_rem_i64, + SHIFT_IMM_ASR(31)); + break; + case INDEX_op_divu2_i32: + tcg_out_div_helper(s, COND_AL, args, + tcg_helper_divu_i64, tcg_helper_remu_i64, + SHIFT_IMM_LSR(31)); + break; + /* XXX: Perhaps args[2] & 0x1f is wrong */ + case INDEX_op_shl_i32: + c = const_args[2] ? + SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); + goto gen_shift32; + case INDEX_op_shr_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); + goto gen_shift32; + case INDEX_op_sar_i32: + c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : + SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); + /* Fall through. */ + gen_shift32: + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); + break; + + case INDEX_op_brcond_i32: + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[0], args[1], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); + break; + case INDEX_op_brcond2_i32: + /* The resulting conditions are: + * TCG_COND_EQ --> a0 == a2 && a1 == a3, + * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3, + * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3, + * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3), + * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3), + * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3, + */ + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, + args[1], args[3], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, + args[0], args[2], SHIFT_IMM_LSL(0)); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, COND_AL, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, COND_AL, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, COND_AL, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, COND_AL, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, COND_AL, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, COND_AL, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, COND_AL, args, 3); + break; + + case INDEX_op_ext8s_i32: +#ifdef __ARM_ARCH_7A__ + /* sxtb */ + tcg_out32(s, 0xe6af0070 | (args[0] << 12) | args[1]); +#else + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(24)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(24)); +#endif + break; + case INDEX_op_ext16s_i32: +#ifdef __ARM_ARCH_7A__ + /* sxth */ + tcg_out32(s, 0xe6bf0070 | (args[0] << 12) | args[1]); +#else + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[1], SHIFT_IMM_LSL(16)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + args[0], 0, args[0], SHIFT_IMM_ASR(16)); +#endif + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef arm_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + /* TODO: "r", "r", "ri" */ + { INDEX_op_add_i32, { "r", "r", "rI" } }, + { INDEX_op_sub_i32, { "r", "r", "rI" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } }, + { INDEX_op_and_i32, { "r", "r", "rI" } }, + { INDEX_op_or_i32, { "r", "r", "rI" } }, + { INDEX_op_xor_i32, { "r", "r", "rI" } }, + { INDEX_op_neg_i32, { "r", "r" } }, + { INDEX_op_not_i32, { "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + + /* TODO: "r", "r", "r", "r", "ri", "ri" */ + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld8s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld16s, { "r", "x", "X" } }, + { INDEX_op_qemu_ld32u, { "r", "x", "X" } }, + { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } }, + + { INDEX_op_qemu_st8, { "x", "x", "X" } }, + { INDEX_op_qemu_st16, { "x", "x", "X" } }, + { INDEX_op_qemu_st32, { "x", "x", "X" } }, + { INDEX_op_qemu_st64, { "x", "D", "x", "X" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, + ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8)); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + ((2 << TCG_REG_R3) - 1) | + (1 << TCG_REG_R12) | (1 << TCG_REG_R14)); + + tcg_regset_clear(s->reserved_regs); +#ifdef SAVE_LR + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8); + + tcg_add_target_add_op_defs(arm_op_defs); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ld32u(s, COND_AL, arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_st32(s, COND_AL, arg, arg1, arg2); +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val > 0) + if (val < 0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val); + else + tcg_abort(); + else if (val < 0) { + if (val > -0x100) + tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val); + else + tcg_abort(); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0)); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_out_movi32(s, COND_AL, ret, arg); +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + /* stmdb sp!, { r9 - r11, lr } */ + tcg_out32(s, (COND_AL << 28) | 0x092d4e00); + + tcg_out_bx(s, COND_AL, TCG_REG_R0); + tb_ret_addr = s->code_ptr; + + /* ldmia sp!, { r9 - r11, pc } */ + tcg_out32(s, (COND_AL << 28) | 0x08bd8e00); +} diff --git a/qemu/qemu-git/tcg/arm/tcg-target.h b/qemu/qemu-git/tcg/arm/tcg-target.h new file mode 100644 index 0000000..71e1ec5 --- /dev/null +++ b/qemu/qemu-git/tcg/arm/tcg-target.h @@ -0,0 +1,85 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * Copyright (c) 2008 Andrzej Zaborowski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_ARM 1 + +#define TCG_TARGET_REG_BITS 32 +#undef TCG_TARGET_WORDS_BIGENDIAN +#undef TCG_TARGET_HAS_div_i32 +#undef TCG_TARGET_HAS_div_i64 +#undef TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_neg_i32 +#undef TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_not_i32 +#undef TCG_TARGET_STACK_GROWSUP + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, +}; + +#define TCG_TARGET_NB_REGS 15 + +#define TCG_CT_CONST_ARM 0x100 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R13 +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +#define TCG_TARGET_HAS_GUEST_BASE + +enum { + /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R7, + TCG_AREG1 = TCG_REG_R4, + TCG_AREG2 = TCG_REG_R5, +}; + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +#if QEMU_GNUC_PREREQ(4, 1) + __builtin___clear_cache((char *) start, (char *) stop); +#else + register unsigned long _beg __asm ("a1") = start; + register unsigned long _end __asm ("a2") = stop; + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +#endif +} diff --git a/qemu/qemu-git/tcg/hppa/.svn/all-wcprops b/qemu/qemu-git/tcg/hppa/.svn/all-wcprops new file mode 100644 index 0000000..5273562 --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/hppa +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/hppa/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/hppa/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/hppa/.svn/entries b/qemu/qemu-git/tcg/hppa/.svn/entries new file mode 100644 index 0000000..f6255b0 --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/hppa +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +3648cf4b85c8da40b9d2ae3c8a3f86ee +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +29464 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +7094eee931532fab56eb908158df4484 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +5645 + diff --git a/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..ddce60c --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,975 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%rp", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", + "%r16", + "%r17", + "%r18", + "%r19", + "%r20", + "%r21", + "%r22", + "%r23", + "%r24", + "%r25", + "%r26", + "%dp", + "%ret0", + "%ret1", + "%sp", + "%r31", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + + TCG_REG_R17, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R26, + TCG_REG_R25, + TCG_REG_R24, + TCG_REG_R23, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RET0, + TCG_REG_RET1, +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_PARISC_PCREL17F: + hppa_patch17f((uint32_t *)code_ptr, value, addend); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + + /* TODO */ + + return 0; +} + +#define INSN_OP(x) ((x) << 26) +#define INSN_EXT3BR(x) ((x) << 13) +#define INSN_EXT3SH(x) ((x) << 10) +#define INSN_EXT4(x) ((x) << 6) +#define INSN_EXT5(x) (x) +#define INSN_EXT6(x) ((x) << 6) +#define INSN_EXT7(x) ((x) << 6) +#define INSN_EXT8A(x) ((x) << 6) +#define INSN_EXT8B(x) ((x) << 5) +#define INSN_T(x) (x) +#define INSN_R1(x) ((x) << 16) +#define INSN_R2(x) ((x) << 21) +#define INSN_DEP_LEN(x) (32 - (x)) +#define INSN_SHDEP_CP(x) ((31 - (x)) << 5) +#define INSN_SHDEP_P(x) ((x) << 5) +#define INSN_COND(x) ((x) << 13) + +#define COND_NEVER 0 +#define COND_EQUAL 1 +#define COND_LT 2 +#define COND_LTEQ 3 +#define COND_LTU 4 +#define COND_LTUEQ 5 +#define COND_SV 6 +#define COND_OD 7 + + +/* Logical ADD */ +#define ARITH_ADD (INSN_OP(0x02) | INSN_EXT6(0x28)) +#define ARITH_AND (INSN_OP(0x02) | INSN_EXT6(0x08)) +#define ARITH_OR (INSN_OP(0x02) | INSN_EXT6(0x09)) +#define ARITH_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a)) +#define ARITH_SUB (INSN_OP(0x02) | INSN_EXT6(0x10)) + +#define SHD (INSN_OP(0x34) | INSN_EXT3SH(2)) +#define VSHD (INSN_OP(0x34) | INSN_EXT3SH(0)) +#define DEP (INSN_OP(0x35) | INSN_EXT3SH(3)) +#define ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2)) +#define ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0)) +#define EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6)) +#define EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7)) +#define VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5)) + +#define SUBI (INSN_OP(0x25)) +#define MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2)) + +#define BL (INSN_OP(0x3a) | INSN_EXT3BR(0)) +#define BLE_SR4 (INSN_OP(0x39) | (1 << 13)) +#define BV (INSN_OP(0x3a) | INSN_EXT3BR(6)) +#define BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2) +#define LDIL (INSN_OP(0x08)) +#define LDO (INSN_OP(0x0d)) + +#define LDB (INSN_OP(0x10)) +#define LDH (INSN_OP(0x11)) +#define LDW (INSN_OP(0x12)) +#define LDWM (INSN_OP(0x13)) + +#define STB (INSN_OP(0x18)) +#define STH (INSN_OP(0x19)) +#define STW (INSN_OP(0x1a)) +#define STWM (INSN_OP(0x1b)) + +#define COMBT (INSN_OP(0x20)) +#define COMBF (INSN_OP(0x22)) + +static int lowsignext(uint32_t val, int start, int length) +{ + return (((val << 1) & ~(~0 << length)) | + ((val >> (length - 1)) & 1)) << start; +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + /* PA1.1 defines COPY as OR r,0,t */ + tcg_out32(s, ARITH_OR | INSN_T(ret) | INSN_R1(arg) | INSN_R2(TCG_REG_R0)); + + /* PA2.0 defines COPY as LDO 0(r),t + * but hppa-dis.c is unaware of this definition */ + /* tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(arg) | reassemble_14(0)); */ +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (arg & 0x1fff)) { + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(TCG_REG_R0) | + reassemble_14(arg)); + } else { + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + if (arg & 0x7ff) + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); + } +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + tcg_out32(s, LDW | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_ld_raw(s, ret, arg); +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, + int op) +{ + if (offset == (offset & 0xfff)) + tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | + reassemble_14(offset)); + else { + fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset); + tcg_abort(); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op) +{ + tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int t, int r1, + tcg_target_long val, int op) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, val); + tcg_out_arith(s, t, r1, TCG_REG_R20, op); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, ARITH_OR | INSN_T(TCG_REG_R0) | INSN_R1(TCG_REG_R0) | + INSN_R2(TCG_REG_R0)); +} + +static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); +} + +static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); +} + +static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) { + if(ret != arg) + tcg_out_mov(s, ret, arg); + tcg_out32(s, DEP | INSN_R2(ret) | INSN_R1(ret) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(TCG_REG_R0) | + INSN_R2(ret) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) { + tcg_out32(s, SHD | INSN_T(temp) | INSN_R1(arg) | + INSN_R2(arg) | INSN_SHDEP_CP(16)); + tcg_out32(s, DEP | INSN_R2(temp) | INSN_R1(temp) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(arg) | + INSN_R2(temp) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_call(TCGContext *s, void *func) +{ + uint32_t val = (uint32_t)__canonicalize_funcptr_for_compare(func); + tcg_out32(s, LDIL | INSN_R2(TCG_REG_R20) | + reassemble_21(lrsel(val, 0))); + tcg_out32(s, BLE_SR4 | INSN_R2(TCG_REG_R20) | + reassemble_17(rrsel(val, 0) >> 2)); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_read), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + +#if TARGET_LONG_BITS == 32 + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R25, mem_index); +#else + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); +#endif + + tcg_out_call(s, qemu_ld_helpers[s_bits]); + + switch(opc) { + case 0 | 4: + tcg_out_ext8s(s, data_reg, TCG_REG_RET0); + break; + case 1 | 4: + tcg_out_ext16s(s, data_reg, TCG_REG_RET0); + break; + case 0: + case 1: + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_RET0); + break; + case 3: + tcg_abort(); + tcg_out_mov(s, data_reg, TCG_REG_RET0); + tcg_out_mov(s, data_reg2, TCG_REG_RET1); + break; + } + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + break; + case 0 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + tcg_out_ext8s(s, data_reg, data_reg); + break; + case 1: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + break; + case 1 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + tcg_out_ext16s(s, data_reg, data_reg); + break; + case 2: + tcg_out_ldst(s, data_reg, r0, 0, LDW); + if (bswap) + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, LDW); + tcg_out_ldst(s, data_reg2, r0, 4, LDW); + } else { + tcg_out_ldst(s, data_reg, r0, 4, LDW); + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + tcg_out_ldst(s, data_reg2, r0, 0, LDW); + tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_write), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + + tcg_out_mov(s, TCG_REG_R26, addr_reg); +#if TARGET_LONG_BITS == 64 + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R24, data_reg); + tcg_out_mov(s, TCG_REG_R23, data_reg2); + /* TODO: push mem_index */ + tcg_abort(); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R24, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } +#else + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R25, data_reg); + tcg_out_mov(s, TCG_REG_R24, data_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R25, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); + } +#endif + tcg_out_call(s, qemu_st_helpers[s_bits]); + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, STB); + break; + case 1: + if (bswap) { + tcg_out_bswap16(s, TCG_REG_R20, data_reg); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STH); + break; + case 2: + if (bswap) { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STW); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, STW); + tcg_out_ldst(s, data_reg2, r0, 4, STW); + } else { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 4, STW); + tcg_out_bswap32(s, TCG_REG_R20, data_reg2, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 0, STW); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R18)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + fprintf(stderr, "goto_tb direct\n"); + tcg_abort(); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_R20, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + tcg_out32(s, BLE_SR4 | INSN_R2(args[0])); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + break; + case INDEX_op_jmp: + fprintf(stderr, "unimplemented jmp\n"); + tcg_abort(); + break; + case INDEX_op_br: + fprintf(stderr, "unimplemented br\n"); + tcg_abort(); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + tcg_out_ext8s(s, args[0], args[0]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + tcg_out_ext16s(s, args[0], args[0]); + break; + case INDEX_op_ld_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDW); + break; + + case INDEX_op_st8_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + case INDEX_op_st16_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + + case INDEX_op_shl_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, ZVDEP | INSN_R2(args[0]) | INSN_R1(args[1]) | + INSN_DEP_LEN(32)); + break; + case INDEX_op_shr_i32: + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(args[2])); + tcg_out32(s, VSHD | INSN_T(args[0]) | INSN_R1(TCG_REG_R0) | + INSN_R2(args[1])); + break; + case INDEX_op_sar_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, VEXTRS | INSN_R1(args[0]) | INSN_R2(args[1]) | + INSN_DEP_LEN(32)); + break; + + case INDEX_op_mul_i32: + fprintf(stderr, "unimplemented mul\n"); + tcg_abort(); + break; + case INDEX_op_mulu2_i32: + fprintf(stderr, "unimplemented mulu2\n"); + tcg_abort(); + break; + case INDEX_op_div2_i32: + fprintf(stderr, "unimplemented div2\n"); + tcg_abort(); + break; + case INDEX_op_divu2_i32: + fprintf(stderr, "unimplemented divu2\n"); + tcg_abort(); + break; + + case INDEX_op_brcond_i32: + fprintf(stderr, "unimplemented brcond\n"); + tcg_abort(); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } + return; + +gen_arith: + tcg_out_arith(s, args[0], args[1], args[2], c); +} + +static const TCGTargetOpDef hppa_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + + { INDEX_op_call, { "r" } }, + { INDEX_op_jmp, { "r" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "r" } }, + { INDEX_op_shr_i32, { "r", "r", "r" } }, + { INDEX_op_sar_i32, { "r", "r", "r" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R20) | + (1 << TCG_REG_R21) | + (1 << TCG_REG_R22) | + (1 << TCG_REG_R23) | + (1 << TCG_REG_R24) | + (1 << TCG_REG_R25) | + (1 << TCG_REG_R26)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* addil target */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP); /* link register */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* frame pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ + + tcg_add_target_add_op_defs(hppa_op_defs); +} diff --git a/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..7ab6f0c --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,203 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define TCG_TARGET_HPPA 1 + +#if defined(_PA_RISC1_1) +#define TCG_TARGET_REG_BITS 32 +#else +#error unsupported +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_RP, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_DP, + TCG_REG_RET0, + TCG_REG_RET1, + TCG_REG_SP, + TCG_REG_R31, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_STACK_GROWSUP + +/* optional instructions */ +//#define TCG_TARGET_HAS_ext8s_i32 +//#define TCG_TARGET_HAS_ext16s_i32 +//#define TCG_TARGET_HAS_bswap16_i32 +//#define TCG_TARGET_HAS_bswap32_i32 + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R17 +#define TCG_AREG1 TCG_REG_R14 +#define TCG_AREG2 TCG_REG_R15 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + start &= ~31; + while (start <= stop) + { + asm volatile ("fdc 0(%0)\n" + "sync\n" + "fic 0(%%sr4, %0)\n" + "sync\n" + : : "r"(start) : "memory"); + start += 32; + } +} + +/* supplied by libgcc */ +extern void *__canonicalize_funcptr_for_compare(void *); + +/* Field selection types defined by hppa */ +#define rnd(x) (((x)+0x1000)&~0x1fff) +/* lsel: select left 21 bits */ +#define lsel(v,a) (((v)+(a))>>11) +/* rsel: select right 11 bits */ +#define rsel(v,a) (((v)+(a))&0x7ff) +/* lrsel with rounding of addend to nearest 8k */ +#define lrsel(v,a) (((v)+rnd(a))>>11) +/* rrsel with rounding of addend to nearest 8k */ +#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) + +#define mask(x,sz) ((x) & ~((1<<(sz))-1)) + +static inline int reassemble_12(int as12) +{ + return (((as12 & 0x800) >> 11) | + ((as12 & 0x400) >> 8) | + ((as12 & 0x3ff) << 3)); +} + +static inline int reassemble_14(int as14) +{ + return (((as14 & 0x1fff) << 1) | + ((as14 & 0x2000) >> 13)); +} + +static inline int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +static inline int reassemble_21(int as21) +{ + return (((as21 & 0x100000) >> 20) | + ((as21 & 0x0ffe00) >> 8) | + ((as21 & 0x000180) << 7) | + ((as21 & 0x00007c) << 14) | + ((as21 & 0x000003) << 12)); +} + +static inline void hppa_patch21l(uint32_t *insn, int val, int addend) +{ + val = lrsel(val, addend); + *insn = mask(*insn, 21) | reassemble_21(val); +} + +static inline void hppa_patch14r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = mask(*insn, 14) | reassemble_14(val); +} + +static inline void hppa_patch17r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); +} + + +static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch21l(insn, val - dp, addend); +} + +static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch14r(insn, val - dp, addend); +} + +static inline void hppa_patch17f(uint32_t *insn, int val, int addend) +{ + int dot = (int)insn & ~0x3; + int v = ((val + addend) - dot - 8) / 4; + if (v > (1 << 16) || v < -(1 << 16)) { + printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); + abort(); + } + *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); +} + +static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) +{ + /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ + *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); +} + +static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) +{ + /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ + hppa_patch14r(insn, val, addend); + /* HACK */ + if (addend == 0) + *insn = (*insn & ~0xfc000000) | (0x0d << 26); +} diff --git a/qemu/qemu-git/tcg/hppa/tcg-target.c b/qemu/qemu-git/tcg/hppa/tcg-target.c new file mode 100644 index 0000000..ddce60c --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/tcg-target.c @@ -0,0 +1,975 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%r0", + "%r1", + "%rp", + "%r3", + "%r4", + "%r5", + "%r6", + "%r7", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", + "%r16", + "%r17", + "%r18", + "%r19", + "%r20", + "%r21", + "%r22", + "%r23", + "%r24", + "%r25", + "%r26", + "%dp", + "%ret0", + "%ret1", + "%sp", + "%r31", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + + TCG_REG_R17, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_R26, + TCG_REG_R25, + TCG_REG_R24, + TCG_REG_R23, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RET0, + TCG_REG_RET1, +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + switch (type) { + case R_PARISC_PCREL17F: + hppa_patch17f((uint32_t *)code_ptr, value, addend); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + + /* TODO */ + + return 0; +} + +#define INSN_OP(x) ((x) << 26) +#define INSN_EXT3BR(x) ((x) << 13) +#define INSN_EXT3SH(x) ((x) << 10) +#define INSN_EXT4(x) ((x) << 6) +#define INSN_EXT5(x) (x) +#define INSN_EXT6(x) ((x) << 6) +#define INSN_EXT7(x) ((x) << 6) +#define INSN_EXT8A(x) ((x) << 6) +#define INSN_EXT8B(x) ((x) << 5) +#define INSN_T(x) (x) +#define INSN_R1(x) ((x) << 16) +#define INSN_R2(x) ((x) << 21) +#define INSN_DEP_LEN(x) (32 - (x)) +#define INSN_SHDEP_CP(x) ((31 - (x)) << 5) +#define INSN_SHDEP_P(x) ((x) << 5) +#define INSN_COND(x) ((x) << 13) + +#define COND_NEVER 0 +#define COND_EQUAL 1 +#define COND_LT 2 +#define COND_LTEQ 3 +#define COND_LTU 4 +#define COND_LTUEQ 5 +#define COND_SV 6 +#define COND_OD 7 + + +/* Logical ADD */ +#define ARITH_ADD (INSN_OP(0x02) | INSN_EXT6(0x28)) +#define ARITH_AND (INSN_OP(0x02) | INSN_EXT6(0x08)) +#define ARITH_OR (INSN_OP(0x02) | INSN_EXT6(0x09)) +#define ARITH_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a)) +#define ARITH_SUB (INSN_OP(0x02) | INSN_EXT6(0x10)) + +#define SHD (INSN_OP(0x34) | INSN_EXT3SH(2)) +#define VSHD (INSN_OP(0x34) | INSN_EXT3SH(0)) +#define DEP (INSN_OP(0x35) | INSN_EXT3SH(3)) +#define ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2)) +#define ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0)) +#define EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6)) +#define EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7)) +#define VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5)) + +#define SUBI (INSN_OP(0x25)) +#define MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2)) + +#define BL (INSN_OP(0x3a) | INSN_EXT3BR(0)) +#define BLE_SR4 (INSN_OP(0x39) | (1 << 13)) +#define BV (INSN_OP(0x3a) | INSN_EXT3BR(6)) +#define BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2) +#define LDIL (INSN_OP(0x08)) +#define LDO (INSN_OP(0x0d)) + +#define LDB (INSN_OP(0x10)) +#define LDH (INSN_OP(0x11)) +#define LDW (INSN_OP(0x12)) +#define LDWM (INSN_OP(0x13)) + +#define STB (INSN_OP(0x18)) +#define STH (INSN_OP(0x19)) +#define STW (INSN_OP(0x1a)) +#define STWM (INSN_OP(0x1b)) + +#define COMBT (INSN_OP(0x20)) +#define COMBF (INSN_OP(0x22)) + +static int lowsignext(uint32_t val, int start, int length) +{ + return (((val << 1) & ~(~0 << length)) | + ((val >> (length - 1)) & 1)) << start; +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + /* PA1.1 defines COPY as OR r,0,t */ + tcg_out32(s, ARITH_OR | INSN_T(ret) | INSN_R1(arg) | INSN_R2(TCG_REG_R0)); + + /* PA2.0 defines COPY as LDO 0(r),t + * but hppa-dis.c is unaware of this definition */ + /* tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(arg) | reassemble_14(0)); */ +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (arg & 0x1fff)) { + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(TCG_REG_R0) | + reassemble_14(arg)); + } else { + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + if (arg & 0x7ff) + tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); + } +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out32(s, LDIL | INSN_R2(ret) | + reassemble_21(lrsel((uint32_t)arg, 0))); + tcg_out32(s, LDW | INSN_R1(ret) | INSN_R2(ret) | + reassemble_14(rrsel((uint32_t)arg, 0))); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_ld_raw(s, ret, arg); +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, + int op) +{ + if (offset == (offset & 0xfff)) + tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | + reassemble_14(offset)); + else { + fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset); + tcg_abort(); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + fprintf(stderr, "unimplemented %s\n", __func__); + tcg_abort(); +} + +static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op) +{ + tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int t, int r1, + tcg_target_long val, int op) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, val); + tcg_out_arith(s, t, r1, TCG_REG_R20, op); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, ARITH_OR | INSN_T(TCG_REG_R0) | INSN_R1(TCG_REG_R0) | + INSN_R2(TCG_REG_R0)); +} + +static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); +} + +static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) { + tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); +} + +static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) { + if(ret != arg) + tcg_out_mov(s, ret, arg); + tcg_out32(s, DEP | INSN_R2(ret) | INSN_R1(ret) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(TCG_REG_R0) | + INSN_R2(ret) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) { + tcg_out32(s, SHD | INSN_T(temp) | INSN_R1(arg) | + INSN_R2(arg) | INSN_SHDEP_CP(16)); + tcg_out32(s, DEP | INSN_R2(temp) | INSN_R1(temp) | + INSN_SHDEP_CP(15) | INSN_DEP_LEN(8)); + tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(arg) | + INSN_R2(temp) | INSN_SHDEP_CP(8)); +} + +static inline void tcg_out_call(TCGContext *s, void *func) +{ + uint32_t val = (uint32_t)__canonicalize_funcptr_for_compare(func); + tcg_out32(s, LDIL | INSN_R2(TCG_REG_R20) | + reassemble_21(lrsel(val, 0))); + tcg_out32(s, BLE_SR4 | INSN_R2(TCG_REG_R20) | + reassemble_17(rrsel(val, 0) >> 2)); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_read), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + +#if TARGET_LONG_BITS == 32 + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R25, mem_index); +#else + tcg_out_mov(s, TCG_REG_R26, addr_reg); + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); +#endif + + tcg_out_call(s, qemu_ld_helpers[s_bits]); + + switch(opc) { + case 0 | 4: + tcg_out_ext8s(s, data_reg, TCG_REG_RET0); + break; + case 1 | 4: + tcg_out_ext16s(s, data_reg, TCG_REG_RET0); + break; + case 0: + case 1: + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_RET0); + break; + case 3: + tcg_abort(); + tcg_out_mov(s, data_reg, TCG_REG_RET0); + tcg_out_mov(s, data_reg2, TCG_REG_RET1); + break; + } + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + break; + case 0 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDB); + tcg_out_ext8s(s, data_reg, data_reg); + break; + case 1: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + break; + case 1 | 4: + tcg_out_ldst(s, data_reg, r0, 0, LDH); + if (bswap) + tcg_out_bswap16(s, data_reg, data_reg); + tcg_out_ext16s(s, data_reg, data_reg); + break; + case 2: + tcg_out_ldst(s, data_reg, r0, 0, LDW); + if (bswap) + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, LDW); + tcg_out_ldst(s, data_reg2, r0, 4, LDW); + } else { + tcg_out_ldst(s, data_reg, r0, 4, LDW); + tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + tcg_out_ldst(s, data_reg2, r0, 0, LDW); + tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint32_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; /* suppress warning */ + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_R26; + r1 = TCG_REG_R25; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) | + INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); + + tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD); + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_write), + ARITH_ADD); + + tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW); + +#if TARGET_LONG_BITS == 32 + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ +#else + /* if not equal, jump to label3 */ + label3_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) | + INSN_COND(COND_EQUAL)); + tcg_out_mov(s, r0, addr_reg); /* delay slot */ + + tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW); + + /* if equal, jump to label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) | + INSN_COND(COND_EQUAL)); + tcg_out_nop(s); /* delay slot */ + + /* label3: */ + *label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2); +#endif + + tcg_out_mov(s, TCG_REG_R26, addr_reg); +#if TARGET_LONG_BITS == 64 + tcg_out_mov(s, TCG_REG_R25, addr_reg2); + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R24, data_reg); + tcg_out_mov(s, TCG_REG_R23, data_reg2); + /* TODO: push mem_index */ + tcg_abort(); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R24, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } +#else + if (opc == 3) { + tcg_abort(); + tcg_out_mov(s, TCG_REG_R25, data_reg); + tcg_out_mov(s, TCG_REG_R24, data_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index); + } else { + switch(opc) { + case 0: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(8)); + break; + case 1: + tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) | + INSN_SHDEP_P(31) | INSN_DEP_LEN(16)); + break; + case 2: + tcg_out_mov(s, TCG_REG_R25, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index); + } +#endif + tcg_out_call(s, qemu_st_helpers[s_bits]); + + /* jump to label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2); + + /* label1: */ + *label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2); + + tcg_out_arithi(s, TCG_REG_R20, r1, + offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write), + ARITH_ADD); + tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW); + tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out_ldst(s, data_reg, r0, 0, STB); + break; + case 1: + if (bswap) { + tcg_out_bswap16(s, TCG_REG_R20, data_reg); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STH); + break; + case 2: + if (bswap) { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + data_reg = TCG_REG_R20; + } + tcg_out_ldst(s, data_reg, r0, 0, STW); + break; + case 3: + tcg_abort(); + if (!bswap) { + tcg_out_ldst(s, data_reg, r0, 0, STW); + tcg_out_ldst(s, data_reg2, r0, 4, STW); + } else { + tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 4, STW); + tcg_out_bswap32(s, TCG_REG_R20, data_reg2, TCG_REG_R20); + tcg_out_ldst(s, TCG_REG_R20, r0, 0, STW); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R18)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + fprintf(stderr, "goto_tb direct\n"); + tcg_abort(); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, args[0]); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_R20, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20)); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + tcg_out32(s, BLE_SR4 | INSN_R2(args[0])); + tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31); + break; + case INDEX_op_jmp: + fprintf(stderr, "unimplemented jmp\n"); + tcg_abort(); + break; + case INDEX_op_br: + fprintf(stderr, "unimplemented br\n"); + tcg_abort(); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDB); + tcg_out_ext8s(s, args[0], args[0]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDH); + tcg_out_ext16s(s, args[0], args[0]); + break; + case INDEX_op_ld_i32: + tcg_out_ldst(s, args[0], args[1], args[2], LDW); + break; + + case INDEX_op_st8_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + case INDEX_op_st16_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + goto gen_arith; + + case INDEX_op_shl_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, ZVDEP | INSN_R2(args[0]) | INSN_R1(args[1]) | + INSN_DEP_LEN(32)); + break; + case INDEX_op_shr_i32: + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(args[2])); + tcg_out32(s, VSHD | INSN_T(args[0]) | INSN_R1(TCG_REG_R0) | + INSN_R2(args[1])); + break; + case INDEX_op_sar_i32: + tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) | + lowsignext(0x1f, 0, 11)); + tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20)); + tcg_out32(s, VEXTRS | INSN_R1(args[0]) | INSN_R2(args[1]) | + INSN_DEP_LEN(32)); + break; + + case INDEX_op_mul_i32: + fprintf(stderr, "unimplemented mul\n"); + tcg_abort(); + break; + case INDEX_op_mulu2_i32: + fprintf(stderr, "unimplemented mulu2\n"); + tcg_abort(); + break; + case INDEX_op_div2_i32: + fprintf(stderr, "unimplemented div2\n"); + tcg_abort(); + break; + case INDEX_op_divu2_i32: + fprintf(stderr, "unimplemented divu2\n"); + tcg_abort(); + break; + + case INDEX_op_brcond_i32: + fprintf(stderr, "unimplemented brcond\n"); + tcg_abort(); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } + return; + +gen_arith: + tcg_out_arith(s, args[0], args[1], args[2], c); +} + +static const TCGTargetOpDef hppa_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + + { INDEX_op_call, { "r" } }, + { INDEX_op_jmp, { "r" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "r" } }, + { INDEX_op_shr_i32, { "r", "r", "r" } }, + { INDEX_op_sar_i32, { "r", "r", "r" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R20) | + (1 << TCG_REG_R21) | + (1 << TCG_REG_R22) | + (1 << TCG_REG_R23) | + (1 << TCG_REG_R24) | + (1 << TCG_REG_R25) | + (1 << TCG_REG_R26)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* addil target */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP); /* link register */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* frame pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ + + tcg_add_target_add_op_defs(hppa_op_defs); +} diff --git a/qemu/qemu-git/tcg/hppa/tcg-target.h b/qemu/qemu-git/tcg/hppa/tcg-target.h new file mode 100644 index 0000000..7ab6f0c --- /dev/null +++ b/qemu/qemu-git/tcg/hppa/tcg-target.h @@ -0,0 +1,203 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define TCG_TARGET_HPPA 1 + +#if defined(_PA_RISC1_1) +#define TCG_TARGET_REG_BITS 32 +#else +#error unsupported +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_RP, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_DP, + TCG_REG_RET0, + TCG_REG_RET1, + TCG_REG_SP, + TCG_REG_R31, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_STACK_GROWSUP + +/* optional instructions */ +//#define TCG_TARGET_HAS_ext8s_i32 +//#define TCG_TARGET_HAS_ext16s_i32 +//#define TCG_TARGET_HAS_bswap16_i32 +//#define TCG_TARGET_HAS_bswap32_i32 + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R17 +#define TCG_AREG1 TCG_REG_R14 +#define TCG_AREG2 TCG_REG_R15 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + start &= ~31; + while (start <= stop) + { + asm volatile ("fdc 0(%0)\n" + "sync\n" + "fic 0(%%sr4, %0)\n" + "sync\n" + : : "r"(start) : "memory"); + start += 32; + } +} + +/* supplied by libgcc */ +extern void *__canonicalize_funcptr_for_compare(void *); + +/* Field selection types defined by hppa */ +#define rnd(x) (((x)+0x1000)&~0x1fff) +/* lsel: select left 21 bits */ +#define lsel(v,a) (((v)+(a))>>11) +/* rsel: select right 11 bits */ +#define rsel(v,a) (((v)+(a))&0x7ff) +/* lrsel with rounding of addend to nearest 8k */ +#define lrsel(v,a) (((v)+rnd(a))>>11) +/* rrsel with rounding of addend to nearest 8k */ +#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) + +#define mask(x,sz) ((x) & ~((1<<(sz))-1)) + +static inline int reassemble_12(int as12) +{ + return (((as12 & 0x800) >> 11) | + ((as12 & 0x400) >> 8) | + ((as12 & 0x3ff) << 3)); +} + +static inline int reassemble_14(int as14) +{ + return (((as14 & 0x1fff) << 1) | + ((as14 & 0x2000) >> 13)); +} + +static inline int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +static inline int reassemble_21(int as21) +{ + return (((as21 & 0x100000) >> 20) | + ((as21 & 0x0ffe00) >> 8) | + ((as21 & 0x000180) << 7) | + ((as21 & 0x00007c) << 14) | + ((as21 & 0x000003) << 12)); +} + +static inline void hppa_patch21l(uint32_t *insn, int val, int addend) +{ + val = lrsel(val, addend); + *insn = mask(*insn, 21) | reassemble_21(val); +} + +static inline void hppa_patch14r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = mask(*insn, 14) | reassemble_14(val); +} + +static inline void hppa_patch17r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); +} + + +static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch21l(insn, val - dp, addend); +} + +static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch14r(insn, val - dp, addend); +} + +static inline void hppa_patch17f(uint32_t *insn, int val, int addend) +{ + int dot = (int)insn & ~0x3; + int v = ((val + addend) - dot - 8) / 4; + if (v > (1 << 16) || v < -(1 << 16)) { + printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); + abort(); + } + *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); +} + +static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) +{ + /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ + *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); +} + +static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) +{ + /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ + hppa_patch14r(insn, val, addend); + /* HACK */ + if (addend == 0) + *insn = (*insn & ~0xfc000000) | (0x0d << 26); +} diff --git a/qemu/qemu-git/tcg/i386/.svn/all-wcprops b/qemu/qemu-git/tcg/i386/.svn/all-wcprops new file mode 100644 index 0000000..2d55167 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/i386 +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/i386/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/i386/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/i386/.svn/entries b/qemu/qemu-git/tcg/i386/.svn/entries new file mode 100644 index 0000000..17ad076 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/i386 +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +e6cfada3d8e7203f6a2223f242f47b7b +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +36927 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +3f7c3401b361f0d144361293a009fee9 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2167 + diff --git a/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..972b102 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1262 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%eax", + "%ecx", + "%edx", + "%ebx", + "%esp", + "%ebp", + "%esi", + "%edi", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_EAX, + TCG_REG_EDX, + TCG_REG_ECX, + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, + TCG_REG_EBP, +}; + +static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX }; +static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX }; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_386_32: + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + *(uint32_t *)code_ptr = value - (long)code_ptr; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + flags &= TCG_CALL_TYPE_MASK; + switch(flags) { + case TCG_CALL_TYPE_STD: + return 0; + case TCG_CALL_TYPE_REGPARM_1: + case TCG_CALL_TYPE_REGPARM_2: + case TCG_CALL_TYPE_REGPARM: + return flags - TCG_CALL_TYPE_REGPARM_1 + 1; + default: + tcg_abort(); + } +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + break; + + /* qemu_ld/st address constraint */ + case 'L': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_ROL 0 +#define SHIFT_ROR 1 +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static inline void tcg_out_opc(TCGContext *s, int opc) +{ + if (opc & P_EXT) + tcg_out8(s, 0x0f); + tcg_out8(s, opc); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc); + tcg_out8(s, 0xc0 | (r << 3) | rm); +} + +/* rm == -1 means no register index */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + int32_t offset) +{ + tcg_out_opc(s, opc); + if (rm == -1) { + tcg_out8(s, 0x05 | (r << 3)); + tcg_out32(s, offset); + } else if (offset == 0 && rm != TCG_REG_EBP) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x04 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | (r << 3) | rm); + } + } else if ((int8_t)offset == offset) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x44 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | (r << 3) | rm); + } + tcg_out8(s, offset); + } else { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x84 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | (r << 3) | rm); + } + tcg_out32(s, offset); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + if (arg != ret) + tcg_out_modrm(s, 0x8b, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, int32_t arg) +{ + if (arg == 0) { + /* xor r0,r0 */ + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); + } else { + tcg_out8(s, 0xb8 + ret); + tcg_out32(s, arg); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); +} + +static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val, int cf) +{ + if (!cf && ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1))) { + /* inc */ + tcg_out_opc(s, 0x40 + r0); + } else if (!cf && ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1))) { + /* dec */ + tcg_out_opc(s, 0x48 + r0); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu && r0 < 4) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi(s, ARITH_ADD, reg, val, 0); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85, arg1, arg1); + } else { + tgen_arithi(s, ARITH_CMP, arg1, arg2, 0); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2(TCGContext *s, + const TCGArg *args, const int *const_args) +{ + int label_next; + label_next = gen_new_label(); + switch(args[4]) { + case TCG_COND_EQ: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_NE: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_LT: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LE: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GT: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GE: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LTU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GTU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + default: + tcg_abort(); + } + tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#ifndef CONFIG_USER_ONLY +#define GUEST_BASE 0 +#endif + +/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and + EAX. It will be useful once fixed registers globals are less + common. */ +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index); +#else + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); +#endif + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + + switch(opc) { + case 0 | 4: + /* movsbl */ + tcg_out_modrm(s, 0xbe | P_EXT, data_reg, TCG_REG_EAX); + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, TCG_REG_EAX); + break; + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, data_reg, TCG_REG_EAX); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, data_reg, TCG_REG_EAX); + break; + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_EAX); + break; + case 3: + if (data_reg == TCG_REG_EDX) { + tcg_out_opc(s, 0x90 + TCG_REG_EDX); /* xchg %edx, %eax */ + tcg_out_mov(s, data_reg2, TCG_REG_EAX); + } else { + tcg_out_mov(s, data_reg, TCG_REG_EAX); + tcg_out_mov(s, data_reg2, TCG_REG_EDX); + } + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE); + break; + case 0 | 4: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswl data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, data_reg); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + } + break; + case 3: + /* XXX: could be nicer */ + if (r0 == data_reg) { + r1 = TCG_REG_EDX; + if (r1 == data_reg) + r1 = TCG_REG_EAX; + tcg_out_mov(s, r1, r0); + r0 = r1; + } + if (!bswap) { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE + 4); + } else { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4); + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE); + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, data_reg); + tcg_out_mov(s, TCG_REG_ECX, data_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } else { + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_EDX, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + } +#else + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out_opc(s, 0x50 + data_reg2); /* push */ + tcg_out_opc(s, 0x50 + data_reg); /* push */ + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 12); + } else { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_ECX, data_reg); + break; + } + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } +#endif + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE); + break; + case 1: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + break; + case 2: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg2); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE); + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4); + } else { + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]); + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out8(s, 0xe8); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out8(s, 0xe9); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + /* movb */ + tcg_out_modrm_offset(s, 0x88, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith: + if (const_args[2]) { + tgen_arithi(s, c, args[0], args[2], 0); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mulu2_i32: + tcg_out_modrm(s, 0xf7, 4, args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + case INDEX_op_rotl_i32: + c = SHIFT_ROL; + goto gen_shift32; + case INDEX_op_rotr_i32: + c = SHIFT_ROR; + goto gen_shift32; + + case INDEX_op_add2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_ADD, args[0], args[4], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADD << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_ADC, args[1], args[5], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADC << 3), args[5], args[1]); + break; + case INDEX_op_sub2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_SUB, args[0], args[4], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_SUB << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_SBB, args[1], args[5], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); + break; + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_bswap16_i32: + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]); + tcg_out8(s, 8); + break; + case INDEX_op_bswap32_i32: + tcg_out_opc(s, (0xc8 + args[0]) | P_EXT); + break; + + case INDEX_op_neg_i32: + tcg_out_modrm(s, 0xf7, 3, args[0]); + break; + + case INDEX_op_not_i32: + tcg_out_modrm(s, 0xf7, 2, args[0]); + break; + + case INDEX_op_ext8s_i32: + tcg_out_modrm(s, 0xbe | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext8u_i32: + tcg_out_modrm(s, 0xb6 | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext16u_i32: + tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "q", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + { INDEX_op_rotl_i32, { "r", "0", "ci" } }, + { INDEX_op_rotr_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, + + { INDEX_op_bswap16_i32, { "r", "0" } }, + { INDEX_op_bswap32_i32, { "r", "0" } }, + + { INDEX_op_neg_i32, { "r", "0" } }, + + { INDEX_op_not_i32, { "r", "0" } }, + + { INDEX_op_ext8s_i32, { "r", "q" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8u_i32, { "r", "q"} }, + { INDEX_op_ext16u_i32, { "r", "r"} }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +static int tcg_target_callee_save_regs[] = { + /* TCG_REG_EBP, */ /* currently used for the global env, so no + need to save */ + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x50 + reg); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x58 + reg); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + } + /* reserve some stack space */ + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_ESP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_EAX) | + (1 << TCG_REG_EDX) | + (1 << TCG_REG_ECX)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP); + + tcg_add_target_add_op_defs(x86_op_defs); +} diff --git a/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..69227c3 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,67 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_I386 1 + +#define TCG_TARGET_REG_BITS 32 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 8 + +enum { + TCG_REG_EAX = 0, + TCG_REG_ECX, + TCG_REG_EDX, + TCG_REG_EBX, + TCG_REG_ESP, + TCG_REG_EBP, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_ESP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_bswap16_i32 +#define TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_not_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_ext8u_i32 +#define TCG_TARGET_HAS_ext16u_i32 + +#define TCG_TARGET_HAS_GUEST_BASE + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_EBP +#define TCG_AREG1 TCG_REG_EBX +#define TCG_AREG2 TCG_REG_ESI + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/qemu-git/tcg/i386/tcg-target.c b/qemu/qemu-git/tcg/i386/tcg-target.c new file mode 100644 index 0000000..972b102 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/tcg-target.c @@ -0,0 +1,1262 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%eax", + "%ecx", + "%edx", + "%ebx", + "%esp", + "%ebp", + "%esi", + "%edi", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_EAX, + TCG_REG_EDX, + TCG_REG_ECX, + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, + TCG_REG_EBP, +}; + +static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX }; +static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX }; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_386_32: + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + *(uint32_t *)code_ptr = value - (long)code_ptr; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + flags &= TCG_CALL_TYPE_MASK; + switch(flags) { + case TCG_CALL_TYPE_STD: + return 0; + case TCG_CALL_TYPE_REGPARM_1: + case TCG_CALL_TYPE_REGPARM_2: + case TCG_CALL_TYPE_REGPARM: + return flags - TCG_CALL_TYPE_REGPARM_1 + 1; + default: + tcg_abort(); + } +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + break; + + /* qemu_ld/st address constraint */ + case 'L': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX); + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_ROL 0 +#define SHIFT_ROR 1 +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static inline void tcg_out_opc(TCGContext *s, int opc) +{ + if (opc & P_EXT) + tcg_out8(s, 0x0f); + tcg_out8(s, opc); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc); + tcg_out8(s, 0xc0 | (r << 3) | rm); +} + +/* rm == -1 means no register index */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + int32_t offset) +{ + tcg_out_opc(s, opc); + if (rm == -1) { + tcg_out8(s, 0x05 | (r << 3)); + tcg_out32(s, offset); + } else if (offset == 0 && rm != TCG_REG_EBP) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x04 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | (r << 3) | rm); + } + } else if ((int8_t)offset == offset) { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x44 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | (r << 3) | rm); + } + tcg_out8(s, offset); + } else { + if (rm == TCG_REG_ESP) { + tcg_out8(s, 0x84 | (r << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | (r << 3) | rm); + } + tcg_out32(s, offset); + } +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + if (arg != ret) + tcg_out_modrm(s, 0x8b, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, int32_t arg) +{ + if (arg == 0) { + /* xor r0,r0 */ + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); + } else { + tcg_out8(s, 0xb8 + ret); + tcg_out32(s, arg); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + /* movl */ + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); +} + +static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val, int cf) +{ + if (!cf && ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1))) { + /* inc */ + tcg_out_opc(s, 0x40 + r0); + } else if (!cf && ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1))) { + /* dec */ + tcg_out_opc(s, 0x48 + r0); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu && r0 < 4) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi(s, ARITH_ADD, reg, val, 0); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85, arg1, arg1); + } else { + tgen_arithi(s, ARITH_CMP, arg1, arg2, 0); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2(TCGContext *s, + const TCGArg *args, const int *const_args) +{ + int label_next; + label_next = gen_new_label(); + switch(args[4]) { + case TCG_COND_EQ: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_NE: + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); + break; + case TCG_COND_LT: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LE: + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GT: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GE: + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LTU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GTU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + break; + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); + tcg_out_jxx(s, JCC_JNE, label_next); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + break; + default: + tcg_abort(); + } + tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#ifndef CONFIG_USER_ONLY +#define GUEST_BASE 0 +#endif + +/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and + EAX. It will be useful once fixed registers globals are less + common. */ +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index); +#else + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); +#endif + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + + switch(opc) { + case 0 | 4: + /* movsbl */ + tcg_out_modrm(s, 0xbe | P_EXT, data_reg, TCG_REG_EAX); + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, TCG_REG_EAX); + break; + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, data_reg, TCG_REG_EAX); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, data_reg, TCG_REG_EAX); + break; + case 2: + default: + tcg_out_mov(s, data_reg, TCG_REG_EAX); + break; + case 3: + if (data_reg == TCG_REG_EDX) { + tcg_out_opc(s, 0x90 + TCG_REG_EDX); /* xchg %edx, %eax */ + tcg_out_mov(s, data_reg2, TCG_REG_EAX); + } else { + tcg_out_mov(s, data_reg, TCG_REG_EAX); + tcg_out_mov(s, data_reg2, TCG_REG_EDX); + } + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE); + break; + case 0 | 4: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswl data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT, data_reg, data_reg); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + } + break; + case 3: + /* XXX: could be nicer */ + if (r0 == data_reg) { + r1 = TCG_REG_EDX; + if (r1 == data_reg) + r1 = TCG_REG_EAX; + tcg_out_mov(s, r1, r0); + r0 = r1; + } + if (!bswap) { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE + 4); + } else { + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4); + tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); + + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE); + /* bswap */ + tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 +#if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +#endif + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_EAX; + r1 = TCG_REG_EDX; + +#if defined(CONFIG_SOFTMMU) + tcg_out_mov(s, r1, addr_reg); + + tcg_out_mov(s, r0, addr_reg); + + tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */ + tcg_out8(s, 0x80 | (r1 << 3) | 0x04); + tcg_out8(s, (5 << 3) | r1); + tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b, r0, r1, 0); + + tcg_out_mov(s, r0, addr_reg); + +#if TARGET_LONG_BITS == 32 + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; +#else + /* jne label3 */ + tcg_out8(s, 0x70 + JCC_JNE); + label3_ptr = s->code_ptr; + s->code_ptr++; + + /* cmp 4(r1), addr_reg2 */ + tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* label3: */ + *label3_ptr = s->code_ptr - label3_ptr - 1; +#endif + + /* XXX: move that code at the end of the TB */ +#if TARGET_LONG_BITS == 32 + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, data_reg); + tcg_out_mov(s, TCG_REG_ECX, data_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } else { + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_EDX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_EDX, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + } +#else + if (opc == 3) { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out_opc(s, 0x50 + data_reg2); /* push */ + tcg_out_opc(s, 0x50 + data_reg); /* push */ + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 12); + } else { + tcg_out_mov(s, TCG_REG_EDX, addr_reg2); + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_ECX, data_reg); + break; + case 2: + tcg_out_mov(s, TCG_REG_ECX, data_reg); + break; + } + tcg_out8(s, 0x6a); /* push Ib */ + tcg_out8(s, mem_index); + tcg_out8(s, 0xe8); + tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - + (tcg_target_long)s->code_ptr - 4); + tcg_out_addi(s, TCG_REG_ESP, 4); + } +#endif + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE); + break; + case 1: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + break; + case 2: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg2); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE); + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT); + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4); + } else { + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]); + tcg_out8(s, 0xe9); /* jmp tb_ret_addr */ + tcg_out32(s, tb_ret_addr - s->code_ptr - 4); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out8(s, 0xe8); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out8(s, 0xe9); + tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + /* movb */ + tcg_out_modrm_offset(s, 0x88, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith: + if (const_args[2]) { + tgen_arithi(s, c, args[0], args[2], 0); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mulu2_i32: + tcg_out_modrm(s, 0xf7, 4, args[3]); + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + case INDEX_op_rotl_i32: + c = SHIFT_ROL; + goto gen_shift32; + case INDEX_op_rotr_i32: + c = SHIFT_ROR; + goto gen_shift32; + + case INDEX_op_add2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_ADD, args[0], args[4], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADD << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_ADC, args[1], args[5], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_ADC << 3), args[5], args[1]); + break; + case INDEX_op_sub2_i32: + if (const_args[4]) + tgen_arithi(s, ARITH_SUB, args[0], args[4], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_SUB << 3), args[4], args[0]); + if (const_args[5]) + tgen_arithi(s, ARITH_SBB, args[1], args[5], 1); + else + tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); + break; + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_bswap16_i32: + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]); + tcg_out8(s, 8); + break; + case INDEX_op_bswap32_i32: + tcg_out_opc(s, (0xc8 + args[0]) | P_EXT); + break; + + case INDEX_op_neg_i32: + tcg_out_modrm(s, 0xf7, 3, args[0]); + break; + + case INDEX_op_not_i32: + tcg_out_modrm(s, 0xf7, 2, args[0]); + break; + + case INDEX_op_ext8s_i32: + tcg_out_modrm(s, 0xbe | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext8u_i32: + tcg_out_modrm(s, 0xb6 | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext16u_i32: + tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "q", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + { INDEX_op_rotl_i32, { "r", "0", "ci" } }, + { INDEX_op_rotr_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, + + { INDEX_op_bswap16_i32, { "r", "0" } }, + { INDEX_op_bswap32_i32, { "r", "0" } }, + + { INDEX_op_neg_i32, { "r", "0" } }, + + { INDEX_op_not_i32, { "r", "0" } }, + + { INDEX_op_ext8s_i32, { "r", "q" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8u_i32, { "r", "q"} }, + { INDEX_op_ext16u_i32, { "r", "r"} }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } }, + + { INDEX_op_qemu_st8, { "cb", "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, +#endif + { -1 }, +}; + +static int tcg_target_callee_save_regs[] = { + /* TCG_REG_EBP, */ /* currently used for the global env, so no + need to save */ + TCG_REG_EBX, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x50 + reg); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, 0x58 + reg); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + } + /* reserve some stack space */ + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_ESP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_EAX) | + (1 << TCG_REG_EDX) | + (1 << TCG_REG_ECX)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP); + + tcg_add_target_add_op_defs(x86_op_defs); +} diff --git a/qemu/qemu-git/tcg/i386/tcg-target.h b/qemu/qemu-git/tcg/i386/tcg-target.h new file mode 100644 index 0000000..69227c3 --- /dev/null +++ b/qemu/qemu-git/tcg/i386/tcg-target.h @@ -0,0 +1,67 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_I386 1 + +#define TCG_TARGET_REG_BITS 32 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 8 + +enum { + TCG_REG_EAX = 0, + TCG_REG_ECX, + TCG_REG_EDX, + TCG_REG_EBX, + TCG_REG_ESP, + TCG_REG_EBP, + TCG_REG_ESI, + TCG_REG_EDI, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_ESP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_bswap16_i32 +#define TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_not_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_ext8u_i32 +#define TCG_TARGET_HAS_ext16u_i32 + +#define TCG_TARGET_HAS_GUEST_BASE + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_EBP +#define TCG_AREG1 TCG_REG_EBX +#define TCG_AREG2 TCG_REG_ESI + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/qemu-git/tcg/mips/.svn/all-wcprops b/qemu/qemu-git/tcg/mips/.svn/all-wcprops new file mode 100644 index 0000000..e129c1c --- /dev/null +++ b/qemu/qemu-git/tcg/mips/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/mips +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/mips/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/mips/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/mips/.svn/entries b/qemu/qemu-git/tcg/mips/.svn/entries new file mode 100644 index 0000000..245feb8 --- /dev/null +++ b/qemu/qemu-git/tcg/mips/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/mips +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +c32ff2c4b3b3b43bf7ca41220e9fbfaf +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +40459 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +c18f6e092964f5d0f33a12a38e7cf4e8 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3067 + diff --git a/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..8fcb5c9 --- /dev/null +++ b/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1342 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008-2009 Arnaud Patard + * Copyright (c) 2009 Aurelien Jarno + * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) +# define TCG_NEED_BSWAP 0 +#else +# define TCG_NEED_BSWAP 1 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "zero", + "at", + "v0", + "v1", + "a0", + "a1", + "a2", + "a3", + "t0", + "t1", + "t2", + "t3", + "t4", + "t5", + "t6", + "t7", + "s0", + "s1", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "t8", + "t9", + "k0", + "k1", + "gp", + "sp", + "fp", + "ra", +}; +#endif + +/* check if we really need so many registers :P */ +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_T1, + TCG_REG_T2, + TCG_REG_T3, + TCG_REG_T4, + TCG_REG_T5, + TCG_REG_T6, + TCG_REG_T7, + TCG_REG_T8, + TCG_REG_T9, + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3, + TCG_REG_V0, + TCG_REG_V1 +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_V0, + TCG_REG_V1 +}; + +static uint8_t *tb_ret_addr; + +static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target) +{ + return target & 0xffff; +} + +static inline void reloc_lo16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_lo16_val(pc, target); +} + +static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target) +{ + return (target >> 16) & 0xffff; +} + +static inline void reloc_hi16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_hi16_val(pc, target); +} + +static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target) +{ + int32_t disp; + + disp = target - (tcg_target_long) pc - 4; + if (disp != (disp << 14) >> 14) { + tcg_abort (); + } + + return (disp >> 2) & 0xffff; +} + +static inline void reloc_pc16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_pc16_val(pc, target); +} + +static inline uint32_t reloc_26_val (void *pc, tcg_target_long target) +{ + if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) { + tcg_abort (); + } + + return (target >> 2) & 0x3ffffff; +} + +static inline void reloc_pc26 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff) + | reloc_26_val(pc, target); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_MIPS_LO16: + reloc_lo16(code_ptr, value); + break; + case R_MIPS_HI16: + reloc_hi16(code_ptr, value); + break; + case R_MIPS_PC16: + reloc_pc16(code_ptr, value); + break; + case R_MIPS_26: + reloc_pc26(code_ptr, value); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); + break; + case 'C': + ct->ct |= TCG_CT_REG; + tcg_regset_clear(ct->u.regs); + tcg_regset_set_reg(ct->u.regs, TCG_REG_T9); + break; + case 'L': /* qemu_ld output arg constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0); + break; + case 'l': /* qemu_ld input arg constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); +#if defined(CONFIG_SOFTMMU) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); +#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); +#if defined(CONFIG_SOFTMMU) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); +# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1); +# endif + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2); +#endif + break; + case 'I': + ct->ct |= TCG_CT_CONST_U16; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S16; + break; + case 'Z': + /* We are cheating a bit here, using the fact that the register + ZERO is also the register number 0. Hence there is no need + to check for const_args in each instruction. */ + ct->ct |= TCG_CT_CONST_ZERO; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_ZERO) && val == 0) + return 1; + else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) + return 1; + else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) + return 1; + else + return 0; +} + +/* instruction opcodes */ +enum { + OPC_SPECIAL = 0x00 << 26, + OPC_BEQ = 0x04 << 26, + OPC_BNE = 0x05 << 26, + OPC_ADDIU = 0x09 << 26, + OPC_ANDI = 0x0C << 26, + OPC_ORI = 0x0D << 26, + OPC_XORI = 0x0E << 26, + OPC_LUI = 0x0F << 26, + OPC_LB = 0x20 << 26, + OPC_LH = 0x21 << 26, + OPC_LW = 0x23 << 26, + OPC_LBU = 0x24 << 26, + OPC_LHU = 0x25 << 26, + OPC_LWU = 0x27 << 26, + OPC_SB = 0x28 << 26, + OPC_SH = 0x29 << 26, + OPC_SW = 0x2B << 26, + OPC_SLL = OPC_SPECIAL | 0x00, + OPC_SRL = OPC_SPECIAL | 0x02, + OPC_SRA = OPC_SPECIAL | 0x03, + OPC_SLLV = OPC_SPECIAL | 0x04, + OPC_SRLV = OPC_SPECIAL | 0x06, + OPC_SRAV = OPC_SPECIAL | 0x07, + OPC_JR = OPC_SPECIAL | 0x08, + OPC_JALR = OPC_SPECIAL | 0x09, + OPC_MFHI = OPC_SPECIAL | 0x10, + OPC_MFLO = OPC_SPECIAL | 0x12, + OPC_MULT = OPC_SPECIAL | 0x18, + OPC_MULTU = OPC_SPECIAL | 0x19, + OPC_DIV = OPC_SPECIAL | 0x1A, + OPC_DIVU = OPC_SPECIAL | 0x1B, + OPC_ADDU = OPC_SPECIAL | 0x21, + OPC_SUBU = OPC_SPECIAL | 0x23, + OPC_AND = OPC_SPECIAL | 0x24, + OPC_OR = OPC_SPECIAL | 0x25, + OPC_XOR = OPC_SPECIAL | 0x26, + OPC_NOR = OPC_SPECIAL | 0x27, + OPC_SLT = OPC_SPECIAL | 0x2A, + OPC_SLTU = OPC_SPECIAL | 0x2B, +}; + +/* + * Type reg + */ +static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt) +{ + int32_t inst; + + inst = opc; + inst |= (rs & 0x1F) << 21; + inst |= (rt & 0x1F) << 16; + inst |= (rd & 0x1F) << 11; + tcg_out32(s, inst); +} + +/* + * Type immediate + */ +static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm) +{ + int32_t inst; + + inst = opc; + inst |= (rs & 0x1F) << 21; + inst |= (rt & 0x1F) << 16; + inst |= (imm & 0xffff); + tcg_out32(s, inst); +} + +/* + * Type sa + */ +static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa) +{ + int32_t inst; + + inst = opc; + inst |= (rt & 0x1F) << 16; + inst |= (rd & 0x1F) << 11; + inst |= (sa & 0x1F) << 6; + tcg_out32(s, inst); + +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, 0); +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int reg, int32_t arg) +{ + if (arg == (int16_t)arg) { + tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg); + } else if (arg == (uint16_t)arg) { + tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg); + } else { + tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16); + tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff); + } +} + +static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) +{ + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff); + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg) +{ + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff); + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg) +{ + /* ret and arg must be different and can't be register at */ + if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00); + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_ldst(TCGContext *s, int opc, int arg, + int arg1, tcg_target_long arg2) +{ + if (arg2 == (int16_t) arg2) { + tcg_out_opc_imm(s, opc, arg, arg1, arg2); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1); + tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, OPC_LW, arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, OPC_SW, arg, arg1, arg2); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val == (int16_t)val) { + tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val); + tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT); + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, int arg1, + int arg2, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + switch (cond) { + case TCG_COND_EQ: + tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0); + break; + case TCG_COND_NE: + tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0); + break; + case TCG_COND_LT: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GE: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LE: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GT: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + default: + tcg_abort(); + break; + } + if (l->has_value) { + reloc_pc16(s->code_ptr - 4, l->u.value); + } else { + tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0); + } + tcg_out_nop(s); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2(TCGContext *s, int cond, int arg1, + int arg2, int arg3, int arg4, int label_index) +{ + void *label_ptr; + + switch(cond) { + case TCG_COND_NE: + tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index); + tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index); + return; + case TCG_COND_EQ: + break; + case TCG_COND_LT: + case TCG_COND_LE: + tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index); + break; + case TCG_COND_GT: + case TCG_COND_GE: + tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index); + break; + case TCG_COND_LTU: + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index); + break; + case TCG_COND_GTU: + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index); + break; + default: + tcg_abort(); + } + + label_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0); + tcg_out_nop(s); + + switch(cond) { + case TCG_COND_EQ: + tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index); + break; + case TCG_COND_LT: + case TCG_COND_LTU: + tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index); + break; + case TCG_COND_LE: + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index); + break; + case TCG_COND_GT: + case TCG_COND_GTU: + tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index); + break; + case TCG_COND_GE: + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index); + break; + default: + tcg_abort(); + } + + reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_regl, addr_reg1, addr_meml; + int data_regl, data_regh, data_reg1, data_reg2; + int mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + void *label1_ptr, *label2_ptr; + int sp_args; +#endif +#if TARGET_LONG_BITS == 64 +# if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +# endif + int addr_regh, addr_reg2, addr_memh; +#endif + data_regl = *args++; + if (opc == 3) + data_regh = *args++; + else + data_regh = 0; + addr_regl = *args++; +#if TARGET_LONG_BITS == 64 + addr_regh = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + if (opc == 3) { +#if defined(TCG_TARGET_WORDS_BIGENDIAN) + data_reg1 = data_regh; + data_reg2 = data_regl; +#else + data_reg1 = data_regl; + data_reg2 = data_regh; +#endif + } else { + data_reg1 = data_regl; + data_reg2 = 0; + } +#if TARGET_LONG_BITS == 64 +# if defined(TCG_TARGET_WORDS_BIGENDIAN) + addr_reg1 = addr_regh; + addr_reg2 = addr_regl; + addr_memh = 0; + addr_meml = 4; +# else + addr_reg1 = addr_regl; + addr_reg2 = addr_regh; + addr_memh = 4; + addr_meml = 0; +# endif +#else + addr_reg1 = addr_regl; + addr_meml = 0; +#endif + +#if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); + +# if TARGET_LONG_BITS == 64 + label3_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh); + + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_nop(s); + + reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); +# else + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); +# endif + + /* slow path */ + sp_args = TCG_REG_A0; + tcg_out_mov(s, sp_args++, addr_reg1); +# if TARGET_LONG_BITS == 64 + tcg_out_mov(s, sp_args++, addr_reg2); +# endif + tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]); + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); + tcg_out_nop(s); + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff); + break; + case 0 | 4: + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 24); + tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 24); + break; + case 1: + tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff); + break; + case 1 | 4: + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 16); + tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 16); + break; + case 2: + tcg_out_mov(s, data_reg1, TCG_REG_V0); + break; + case 3: + tcg_out_mov(s, data_reg2, TCG_REG_V1); + tcg_out_mov(s, data_reg1, TCG_REG_V0); + break; + default: + tcg_abort(); + } + + label2_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_nop(s); + + /* label1: fast path */ + reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl); + + addr_reg1 = TCG_REG_V0; +#endif + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_LBU, data_reg1, addr_reg1, 0); + break; + case 0 | 4: + tcg_out_opc_imm(s, OPC_LB, data_reg1, addr_reg1, 0); + break; + case 1: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap16(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LHU, data_reg1, addr_reg1, 0); + } + break; + case 1 | 4: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap16s(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LH, data_reg1, addr_reg1, 0); + } + break; + case 2: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); + } + break; + case 3: +#if !defined(CONFIG_SOFTMMU) + tcg_out_mov(s, TCG_REG_V0, addr_reg1); + addr_reg1 = TCG_REG_V0; +#endif + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 4); + tcg_out_bswap32(s, data_reg1, TCG_REG_T0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, data_reg2, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); + tcg_out_opc_imm(s, OPC_LW, data_reg2, addr_reg1, 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_regl, addr_reg1, addr_meml; + int data_regl, data_regh, data_reg1, data_reg2; + int mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; + int sp_args; +#endif +#if TARGET_LONG_BITS == 64 +# if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +# endif + int addr_regh, addr_reg2, addr_memh; +#endif + + data_regl = *args++; + if (opc == 3) { + data_regh = *args++; +#if defined(TCG_TARGET_WORDS_BIGENDIAN) + data_reg1 = data_regh; + data_reg2 = data_regl; +#else + data_reg1 = data_regl; + data_reg2 = data_regh; +#endif + } else { + data_reg1 = data_regl; + data_reg2 = 0; + data_regh = 0; + } + addr_regl = *args++; +#if TARGET_LONG_BITS == 64 + addr_regh = *args++; +# if defined(TCG_TARGET_WORDS_BIGENDIAN) + addr_reg1 = addr_regh; + addr_reg2 = addr_regl; + addr_memh = 0; + addr_meml = 4; +# else + addr_reg1 = addr_regl; + addr_reg2 = addr_regh; + addr_memh = 4; + addr_meml = 0; +# endif +#else + addr_reg1 = addr_regl; + addr_meml = 0; +#endif + mem_index = *args; + s_bits = opc; + +#if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); + +# if TARGET_LONG_BITS == 64 + label3_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh); + + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_nop(s); + + reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); +# else + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); +# endif + + /* slow path */ + sp_args = TCG_REG_A0; + tcg_out_mov(s, sp_args++, addr_reg1); +# if TARGET_LONG_BITS == 64 + tcg_out_mov(s, sp_args++, addr_reg2); +# endif + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff); + break; + case 1: + tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff); + break; + case 2: + tcg_out_mov(s, sp_args++, data_reg1); + break; + case 3: + sp_args = (sp_args + 1) & ~1; + tcg_out_mov(s, sp_args++, data_reg1); + tcg_out_mov(s, sp_args++, data_reg2); + break; + default: + tcg_abort(); + } + if (sp_args > TCG_REG_A3) { + /* Push mem_index on the stack */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index); + tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16); + } else { + tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index); + } + + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]); + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); + tcg_out_nop(s); + + label2_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_nop(s); + + /* label1: fast path */ + reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl); + + addr_reg1 = TCG_REG_A0; +#endif + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_SB, data_reg1, addr_reg1, 0); + break; + case 1: + if (TCG_NEED_BSWAP) { + tcg_out_bswap16(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, addr_reg1, 0); + } else { + tcg_out_opc_imm(s, OPC_SH, data_reg1, addr_reg1, 0); + } + break; + case 2: + if (TCG_NEED_BSWAP) { + tcg_out_bswap32(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); + } else { + tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); + } + break; + case 3: + if (TCG_NEED_BSWAP) { + tcg_out_bswap32(s, TCG_REG_T0, data_reg2); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 4); + } else { + tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); + tcg_out_opc_imm(s, OPC_SW, data_reg2, addr_reg1, 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); + tcg_out_nop(s); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_abort(); + } else { + /* indirect jump method */ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0])); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); + tcg_out_nop(s); + break; + case INDEX_op_jmp: + tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0); + tcg_out_nop(s); + break; + case INDEX_op_br: + tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); + break; + + case INDEX_op_mov_i32: + tcg_out_mov(s, args[0], args[1]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]); + break; + + case INDEX_op_add_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]); + } + break; + case INDEX_op_add2_i32: + if (const_args[4]) { + tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]); + } + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]); + if (const_args[5]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]); + } + tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0); + tcg_out_mov(s, args[0], TCG_REG_AT); + break; + case INDEX_op_sub_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]); + } + break; + case INDEX_op_sub2_i32: + if (const_args[4]) { + tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]); + } + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT); + if (const_args[5]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]); + } + tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0); + tcg_out_mov(s, args[0], TCG_REG_AT); + break; + case INDEX_op_mul_i32: + tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_mulu2_i32: + tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0); + break; + case INDEX_op_div_i32: + tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_divu_i32: + tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_rem_i32: + tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); + break; + case INDEX_op_remu_i32: + tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); + break; + + case INDEX_op_and_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]); + } + break; + case INDEX_op_or_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]); + } + break; + case INDEX_op_not_i32: + tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[1]); + break; + case INDEX_op_xor_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]); + } + break; + + case INDEX_op_sar_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]); + } + break; + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]); + } + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]); + } + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "C" } }, + { INDEX_op_jmp, { "r" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "rZ", "r" } }, + { INDEX_op_st16_i32, { "rZ", "r" } }, + { INDEX_op_st_i32, { "rZ", "r" } }, + + { INDEX_op_add_i32, { "r", "rZ", "rJZ" } }, + { INDEX_op_mul_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } }, + { INDEX_op_div_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_divu_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_rem_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_remu_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } }, + + { INDEX_op_and_i32, { "r", "rZ", "rIZ" } }, + { INDEX_op_not_i32, { "r", "rZ" } }, + { INDEX_op_or_i32, { "r", "rZ", "rIZ" } }, + { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } }, + + { INDEX_op_shl_i32, { "r", "rZ", "riZ" } }, + { INDEX_op_shr_i32, { "r", "rZ", "riZ" } }, + { INDEX_op_sar_i32, { "r", "rZ", "riZ" } }, + + { INDEX_op_brcond_i32, { "rZ", "rZ" } }, + + { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, + { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, + { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "L", "lZ" } }, + { INDEX_op_qemu_ld8s, { "L", "lZ" } }, + { INDEX_op_qemu_ld16u, { "L", "lZ" } }, + { INDEX_op_qemu_ld16s, { "L", "lZ" } }, + { INDEX_op_qemu_ld32u, { "L", "lZ" } }, + { INDEX_op_qemu_ld64, { "L", "L", "lZ" } }, + + { INDEX_op_qemu_st8, { "SZ", "SZ" } }, + { INDEX_op_qemu_st16, { "SZ", "SZ" } }, + { INDEX_op_qemu_st32, { "SZ", "SZ" } }, + { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } }, +#else + { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld32u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } }, + + { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } }, +#endif + { -1 }, +}; + +static int tcg_target_callee_save_regs[] = { + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_GP, + /* TCG_REG_FP, */ /* currently used for the global env, so np + need to save */ + TCG_REG_RA, /* should be last for ABI compliance */ +}; + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size; + + /* reserve some stack space */ + frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4 + + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + + /* TB prologue */ + tcg_out_addi(s, TCG_REG_SP, -frame_size); + for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { + tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], + TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); + } + + /* Call generated code */ + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0); + tcg_out_nop(s); + tb_ret_addr = s->code_ptr; + + /* TB epilogue */ + for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { + tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], + TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); + } + + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0); + tcg_out_addi(s, TCG_REG_SP, frame_size); +} + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff); + tcg_regset_set(tcg_target_call_clobber_regs, + (1 << TCG_REG_V0) | + (1 << TCG_REG_V1) | + (1 << TCG_REG_A0) | + (1 << TCG_REG_A1) | + (1 << TCG_REG_A2) | + (1 << TCG_REG_A3) | + (1 << TCG_REG_T1) | + (1 << TCG_REG_T2) | + (1 << TCG_REG_T3) | + (1 << TCG_REG_T4) | + (1 << TCG_REG_T5) | + (1 << TCG_REG_T6) | + (1 << TCG_REG_T7) | + (1 << TCG_REG_T8) | + (1 << TCG_REG_T9)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0); /* kernel use only */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1); /* kernel use only */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT); /* internal use */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0); /* internal use */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + + tcg_add_target_add_op_defs(mips_op_defs); +} diff --git a/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..46760a5 --- /dev/null +++ b/qemu/qemu-git/tcg/mips/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,104 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008-2009 Arnaud Patard + * Copyright (c) 2009 Aurelien Jarno + * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_MIPS 1 + +#define TCG_TARGET_REG_BITS 32 +#ifdef __MIPSEB__ +# define TCG_TARGET_WORDS_BIGENDIAN +#endif + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_ZERO = 0, + TCG_REG_AT, + TCG_REG_V0, + TCG_REG_V1, + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3, + TCG_REG_T0, + TCG_REG_T1, + TCG_REG_T2, + TCG_REG_T3, + TCG_REG_T4, + TCG_REG_T5, + TCG_REG_T6, + TCG_REG_T7, + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_T8, + TCG_REG_T9, + TCG_REG_K0, + TCG_REG_K1, + TCG_REG_GP, + TCG_REG_SP, + TCG_REG_FP, + TCG_REG_RA, +}; + +#define TCG_CT_CONST_ZERO 0x100 +#define TCG_CT_CONST_U16 0x200 +#define TCG_CT_CONST_S16 0x400 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 16 +#define TCG_TARGET_CALL_ALIGN_ARGS 1 + +/* optional instructions */ +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_not_i32 +#undef TCG_TARGET_HAS_ext8s_i32 +#undef TCG_TARGET_HAS_ext16s_i32 +#undef TCG_TARGET_HAS_bswap32_i32 +#undef TCG_TARGET_HAS_bswap16_i32 +#undef TCG_TARGET_HAS_rot_i32 + +/* optional instructions automatically implemented */ +#undef TCG_TARGET_HAS_neg_i32 /* sub rd, zero, rt */ +#undef TCG_TARGET_HAS_ext8u_i32 /* andi rt, rs, 0xff */ +#undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */ + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_FP +#define TCG_AREG1 TCG_REG_S0 +#define TCG_AREG2 TCG_REG_S1 + +#include + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + cacheflush ((void *)start, stop-start, ICACHE); +} diff --git a/qemu/qemu-git/tcg/mips/tcg-target.c b/qemu/qemu-git/tcg/mips/tcg-target.c new file mode 100644 index 0000000..8fcb5c9 --- /dev/null +++ b/qemu/qemu-git/tcg/mips/tcg-target.c @@ -0,0 +1,1342 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008-2009 Arnaud Patard + * Copyright (c) 2009 Aurelien Jarno + * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) +# define TCG_NEED_BSWAP 0 +#else +# define TCG_NEED_BSWAP 1 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "zero", + "at", + "v0", + "v1", + "a0", + "a1", + "a2", + "a3", + "t0", + "t1", + "t2", + "t3", + "t4", + "t5", + "t6", + "t7", + "s0", + "s1", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "t8", + "t9", + "k0", + "k1", + "gp", + "sp", + "fp", + "ra", +}; +#endif + +/* check if we really need so many registers :P */ +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_T1, + TCG_REG_T2, + TCG_REG_T3, + TCG_REG_T4, + TCG_REG_T5, + TCG_REG_T6, + TCG_REG_T7, + TCG_REG_T8, + TCG_REG_T9, + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3, + TCG_REG_V0, + TCG_REG_V1 +}; + +static const int tcg_target_call_iarg_regs[4] = { + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_V0, + TCG_REG_V1 +}; + +static uint8_t *tb_ret_addr; + +static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target) +{ + return target & 0xffff; +} + +static inline void reloc_lo16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_lo16_val(pc, target); +} + +static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target) +{ + return (target >> 16) & 0xffff; +} + +static inline void reloc_hi16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_hi16_val(pc, target); +} + +static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target) +{ + int32_t disp; + + disp = target - (tcg_target_long) pc - 4; + if (disp != (disp << 14) >> 14) { + tcg_abort (); + } + + return (disp >> 2) & 0xffff; +} + +static inline void reloc_pc16 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) + | reloc_pc16_val(pc, target); +} + +static inline uint32_t reloc_26_val (void *pc, tcg_target_long target) +{ + if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) { + tcg_abort (); + } + + return (target >> 2) & 0x3ffffff; +} + +static inline void reloc_pc26 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff) + | reloc_26_val(pc, target); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_MIPS_LO16: + reloc_lo16(code_ptr, value); + break; + case R_MIPS_HI16: + reloc_hi16(code_ptr, value); + break; + case R_MIPS_PC16: + reloc_pc16(code_ptr, value); + break; + case R_MIPS_26: + reloc_pc26(code_ptr, value); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 4; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); + break; + case 'C': + ct->ct |= TCG_CT_REG; + tcg_regset_clear(ct->u.regs); + tcg_regset_set_reg(ct->u.regs, TCG_REG_T9); + break; + case 'L': /* qemu_ld output arg constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0); + break; + case 'l': /* qemu_ld input arg constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); +#if defined(CONFIG_SOFTMMU) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); +#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set(ct->u.regs, 0xffffffff); +#if defined(CONFIG_SOFTMMU) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); +# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1); +# endif + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2); +#endif + break; + case 'I': + ct->ct |= TCG_CT_CONST_U16; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S16; + break; + case 'Z': + /* We are cheating a bit here, using the fact that the register + ZERO is also the register number 0. Hence there is no need + to check for const_args in each instruction. */ + ct->ct |= TCG_CT_CONST_ZERO; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_ZERO) && val == 0) + return 1; + else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) + return 1; + else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) + return 1; + else + return 0; +} + +/* instruction opcodes */ +enum { + OPC_SPECIAL = 0x00 << 26, + OPC_BEQ = 0x04 << 26, + OPC_BNE = 0x05 << 26, + OPC_ADDIU = 0x09 << 26, + OPC_ANDI = 0x0C << 26, + OPC_ORI = 0x0D << 26, + OPC_XORI = 0x0E << 26, + OPC_LUI = 0x0F << 26, + OPC_LB = 0x20 << 26, + OPC_LH = 0x21 << 26, + OPC_LW = 0x23 << 26, + OPC_LBU = 0x24 << 26, + OPC_LHU = 0x25 << 26, + OPC_LWU = 0x27 << 26, + OPC_SB = 0x28 << 26, + OPC_SH = 0x29 << 26, + OPC_SW = 0x2B << 26, + OPC_SLL = OPC_SPECIAL | 0x00, + OPC_SRL = OPC_SPECIAL | 0x02, + OPC_SRA = OPC_SPECIAL | 0x03, + OPC_SLLV = OPC_SPECIAL | 0x04, + OPC_SRLV = OPC_SPECIAL | 0x06, + OPC_SRAV = OPC_SPECIAL | 0x07, + OPC_JR = OPC_SPECIAL | 0x08, + OPC_JALR = OPC_SPECIAL | 0x09, + OPC_MFHI = OPC_SPECIAL | 0x10, + OPC_MFLO = OPC_SPECIAL | 0x12, + OPC_MULT = OPC_SPECIAL | 0x18, + OPC_MULTU = OPC_SPECIAL | 0x19, + OPC_DIV = OPC_SPECIAL | 0x1A, + OPC_DIVU = OPC_SPECIAL | 0x1B, + OPC_ADDU = OPC_SPECIAL | 0x21, + OPC_SUBU = OPC_SPECIAL | 0x23, + OPC_AND = OPC_SPECIAL | 0x24, + OPC_OR = OPC_SPECIAL | 0x25, + OPC_XOR = OPC_SPECIAL | 0x26, + OPC_NOR = OPC_SPECIAL | 0x27, + OPC_SLT = OPC_SPECIAL | 0x2A, + OPC_SLTU = OPC_SPECIAL | 0x2B, +}; + +/* + * Type reg + */ +static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt) +{ + int32_t inst; + + inst = opc; + inst |= (rs & 0x1F) << 21; + inst |= (rt & 0x1F) << 16; + inst |= (rd & 0x1F) << 11; + tcg_out32(s, inst); +} + +/* + * Type immediate + */ +static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm) +{ + int32_t inst; + + inst = opc; + inst |= (rs & 0x1F) << 21; + inst |= (rt & 0x1F) << 16; + inst |= (imm & 0xffff); + tcg_out32(s, inst); +} + +/* + * Type sa + */ +static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa) +{ + int32_t inst; + + inst = opc; + inst |= (rt & 0x1F) << 16; + inst |= (rd & 0x1F) << 11; + inst |= (sa & 0x1F) << 6; + tcg_out32(s, inst); + +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out32(s, 0); +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int reg, int32_t arg) +{ + if (arg == (int16_t)arg) { + tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg); + } else if (arg == (uint16_t)arg) { + tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg); + } else { + tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16); + tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff); + } +} + +static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) +{ + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff); + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg) +{ + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff); + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg) +{ + /* ret and arg must be different and can't be register at */ + if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00); + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + +static inline void tcg_out_ldst(TCGContext *s, int opc, int arg, + int arg1, tcg_target_long arg2) +{ + if (arg2 == (int16_t) arg2) { + tcg_out_opc_imm(s, opc, arg, arg1, arg2); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1); + tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, OPC_LW, arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, OPC_SW, arg, arg1, arg2); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val == (int16_t)val) { + tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val); + tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT); + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, int arg1, + int arg2, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + switch (cond) { + case TCG_COND_EQ: + tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0); + break; + case TCG_COND_NE: + tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0); + break; + case TCG_COND_LT: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GE: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LE: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_LEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GT: + tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + case TCG_COND_GTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + break; + default: + tcg_abort(); + break; + } + if (l->has_value) { + reloc_pc16(s->code_ptr - 4, l->u.value); + } else { + tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0); + } + tcg_out_nop(s); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2(TCGContext *s, int cond, int arg1, + int arg2, int arg3, int arg4, int label_index) +{ + void *label_ptr; + + switch(cond) { + case TCG_COND_NE: + tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index); + tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index); + return; + case TCG_COND_EQ: + break; + case TCG_COND_LT: + case TCG_COND_LE: + tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index); + break; + case TCG_COND_GT: + case TCG_COND_GE: + tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index); + break; + case TCG_COND_LTU: + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index); + break; + case TCG_COND_GTU: + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index); + break; + default: + tcg_abort(); + } + + label_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0); + tcg_out_nop(s); + + switch(cond) { + case TCG_COND_EQ: + tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index); + break; + case TCG_COND_LT: + case TCG_COND_LTU: + tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index); + break; + case TCG_COND_LE: + case TCG_COND_LEU: + tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index); + break; + case TCG_COND_GT: + case TCG_COND_GTU: + tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index); + break; + case TCG_COND_GE: + case TCG_COND_GEU: + tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index); + break; + default: + tcg_abort(); + } + + reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_regl, addr_reg1, addr_meml; + int data_regl, data_regh, data_reg1, data_reg2; + int mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + void *label1_ptr, *label2_ptr; + int sp_args; +#endif +#if TARGET_LONG_BITS == 64 +# if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +# endif + int addr_regh, addr_reg2, addr_memh; +#endif + data_regl = *args++; + if (opc == 3) + data_regh = *args++; + else + data_regh = 0; + addr_regl = *args++; +#if TARGET_LONG_BITS == 64 + addr_regh = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + + if (opc == 3) { +#if defined(TCG_TARGET_WORDS_BIGENDIAN) + data_reg1 = data_regh; + data_reg2 = data_regl; +#else + data_reg1 = data_regl; + data_reg2 = data_regh; +#endif + } else { + data_reg1 = data_regl; + data_reg2 = 0; + } +#if TARGET_LONG_BITS == 64 +# if defined(TCG_TARGET_WORDS_BIGENDIAN) + addr_reg1 = addr_regh; + addr_reg2 = addr_regl; + addr_memh = 0; + addr_meml = 4; +# else + addr_reg1 = addr_regl; + addr_reg2 = addr_regh; + addr_memh = 4; + addr_meml = 0; +# endif +#else + addr_reg1 = addr_regl; + addr_meml = 0; +#endif + +#if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); + +# if TARGET_LONG_BITS == 64 + label3_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh); + + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_nop(s); + + reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); +# else + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); +# endif + + /* slow path */ + sp_args = TCG_REG_A0; + tcg_out_mov(s, sp_args++, addr_reg1); +# if TARGET_LONG_BITS == 64 + tcg_out_mov(s, sp_args++, addr_reg2); +# endif + tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]); + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); + tcg_out_nop(s); + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff); + break; + case 0 | 4: + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 24); + tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 24); + break; + case 1: + tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff); + break; + case 1 | 4: + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 16); + tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 16); + break; + case 2: + tcg_out_mov(s, data_reg1, TCG_REG_V0); + break; + case 3: + tcg_out_mov(s, data_reg2, TCG_REG_V1); + tcg_out_mov(s, data_reg1, TCG_REG_V0); + break; + default: + tcg_abort(); + } + + label2_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_nop(s); + + /* label1: fast path */ + reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl); + + addr_reg1 = TCG_REG_V0; +#endif + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_LBU, data_reg1, addr_reg1, 0); + break; + case 0 | 4: + tcg_out_opc_imm(s, OPC_LB, data_reg1, addr_reg1, 0); + break; + case 1: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap16(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LHU, data_reg1, addr_reg1, 0); + } + break; + case 1 | 4: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap16s(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LH, data_reg1, addr_reg1, 0); + } + break; + case 2: + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, data_reg1, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); + } + break; + case 3: +#if !defined(CONFIG_SOFTMMU) + tcg_out_mov(s, TCG_REG_V0, addr_reg1); + addr_reg1 = TCG_REG_V0; +#endif + if (TCG_NEED_BSWAP) { + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 4); + tcg_out_bswap32(s, data_reg1, TCG_REG_T0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, data_reg2, TCG_REG_T0); + } else { + tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0); + tcg_out_opc_imm(s, OPC_LW, data_reg2, addr_reg1, 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_regl, addr_reg1, addr_meml; + int data_regl, data_regh, data_reg1, data_reg2; + int mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; + int sp_args; +#endif +#if TARGET_LONG_BITS == 64 +# if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +# endif + int addr_regh, addr_reg2, addr_memh; +#endif + + data_regl = *args++; + if (opc == 3) { + data_regh = *args++; +#if defined(TCG_TARGET_WORDS_BIGENDIAN) + data_reg1 = data_regh; + data_reg2 = data_regl; +#else + data_reg1 = data_regl; + data_reg2 = data_regh; +#endif + } else { + data_reg1 = data_regl; + data_reg2 = 0; + data_regh = 0; + } + addr_regl = *args++; +#if TARGET_LONG_BITS == 64 + addr_regh = *args++; +# if defined(TCG_TARGET_WORDS_BIGENDIAN) + addr_reg1 = addr_regh; + addr_reg2 = addr_regl; + addr_memh = 0; + addr_meml = 4; +# else + addr_reg1 = addr_regl; + addr_reg2 = addr_regh; + addr_memh = 4; + addr_meml = 0; +# endif +#else + addr_reg1 = addr_regl; + addr_meml = 0; +#endif + mem_index = *args; + s_bits = opc; + +#if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0); + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl); + +# if TARGET_LONG_BITS == 64 + label3_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh); + + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_nop(s); + + reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); +# else + label1_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_nop(s); +# endif + + /* slow path */ + sp_args = TCG_REG_A0; + tcg_out_mov(s, sp_args++, addr_reg1); +# if TARGET_LONG_BITS == 64 + tcg_out_mov(s, sp_args++, addr_reg2); +# endif + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff); + break; + case 1: + tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff); + break; + case 2: + tcg_out_mov(s, sp_args++, data_reg1); + break; + case 3: + sp_args = (sp_args + 1) & ~1; + tcg_out_mov(s, sp_args++, data_reg1); + tcg_out_mov(s, sp_args++, data_reg2); + break; + default: + tcg_abort(); + } + if (sp_args > TCG_REG_A3) { + /* Push mem_index on the stack */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index); + tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16); + } else { + tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index); + } + + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]); + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); + tcg_out_nop(s); + + label2_ptr = s->code_ptr; + tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_nop(s); + + /* label1: fast path */ + reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + + tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, + offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl); + + addr_reg1 = TCG_REG_A0; +#endif + + switch(opc) { + case 0: + tcg_out_opc_imm(s, OPC_SB, data_reg1, addr_reg1, 0); + break; + case 1: + if (TCG_NEED_BSWAP) { + tcg_out_bswap16(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, addr_reg1, 0); + } else { + tcg_out_opc_imm(s, OPC_SH, data_reg1, addr_reg1, 0); + } + break; + case 2: + if (TCG_NEED_BSWAP) { + tcg_out_bswap32(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); + } else { + tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); + } + break; + case 3: + if (TCG_NEED_BSWAP) { + tcg_out_bswap32(s, TCG_REG_T0, data_reg2); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0); + tcg_out_bswap32(s, TCG_REG_T0, data_reg1); + tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 4); + } else { + tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0); + tcg_out_opc_imm(s, OPC_SW, data_reg2, addr_reg1, 4); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); + tcg_out_nop(s); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_abort(); + } else { + /* indirect jump method */ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0])); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); + tcg_out_nop(s); + break; + case INDEX_op_jmp: + tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0); + tcg_out_nop(s); + break; + case INDEX_op_br: + tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); + break; + + case INDEX_op_mov_i32: + tcg_out_mov(s, args[0], args[1]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + + case INDEX_op_ld8u_i32: + tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]); + break; + + case INDEX_op_add_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]); + } + break; + case INDEX_op_add2_i32: + if (const_args[4]) { + tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]); + } + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]); + if (const_args[5]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]); + } else { + tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]); + } + tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0); + tcg_out_mov(s, args[0], TCG_REG_AT); + break; + case INDEX_op_sub_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]); + } + break; + case INDEX_op_sub2_i32: + if (const_args[4]) { + tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]); + } + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT); + if (const_args[5]) { + tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]); + } else { + tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]); + } + tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0); + tcg_out_mov(s, args[0], TCG_REG_AT); + break; + case INDEX_op_mul_i32: + tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_mulu2_i32: + tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0); + break; + case INDEX_op_div_i32: + tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_divu_i32: + tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0); + break; + case INDEX_op_rem_i32: + tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); + break; + case INDEX_op_remu_i32: + tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]); + tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0); + break; + + case INDEX_op_and_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]); + } + break; + case INDEX_op_or_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]); + } + break; + case INDEX_op_not_i32: + tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[1]); + break; + case INDEX_op_xor_i32: + if (const_args[2]) { + tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]); + } + break; + + case INDEX_op_sar_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]); + } + break; + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]); + } + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]); + } else { + tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]); + } + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "C" } }, + { INDEX_op_jmp, { "r" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "rZ", "r" } }, + { INDEX_op_st16_i32, { "rZ", "r" } }, + { INDEX_op_st_i32, { "rZ", "r" } }, + + { INDEX_op_add_i32, { "r", "rZ", "rJZ" } }, + { INDEX_op_mul_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } }, + { INDEX_op_div_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_divu_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_rem_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_remu_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } }, + + { INDEX_op_and_i32, { "r", "rZ", "rIZ" } }, + { INDEX_op_not_i32, { "r", "rZ" } }, + { INDEX_op_or_i32, { "r", "rZ", "rIZ" } }, + { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } }, + + { INDEX_op_shl_i32, { "r", "rZ", "riZ" } }, + { INDEX_op_shr_i32, { "r", "rZ", "riZ" } }, + { INDEX_op_sar_i32, { "r", "rZ", "riZ" } }, + + { INDEX_op_brcond_i32, { "rZ", "rZ" } }, + + { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, + { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, + { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "L", "lZ" } }, + { INDEX_op_qemu_ld8s, { "L", "lZ" } }, + { INDEX_op_qemu_ld16u, { "L", "lZ" } }, + { INDEX_op_qemu_ld16s, { "L", "lZ" } }, + { INDEX_op_qemu_ld32u, { "L", "lZ" } }, + { INDEX_op_qemu_ld64, { "L", "L", "lZ" } }, + + { INDEX_op_qemu_st8, { "SZ", "SZ" } }, + { INDEX_op_qemu_st16, { "SZ", "SZ" } }, + { INDEX_op_qemu_st32, { "SZ", "SZ" } }, + { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } }, +#else + { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld32u, { "L", "lZ", "lZ" } }, + { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } }, + + { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } }, + { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } }, +#endif + { -1 }, +}; + +static int tcg_target_callee_save_regs[] = { + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_GP, + /* TCG_REG_FP, */ /* currently used for the global env, so np + need to save */ + TCG_REG_RA, /* should be last for ABI compliance */ +}; + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size; + + /* reserve some stack space */ + frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4 + + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + + /* TB prologue */ + tcg_out_addi(s, TCG_REG_SP, -frame_size); + for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { + tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], + TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); + } + + /* Call generated code */ + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0); + tcg_out_nop(s); + tb_ret_addr = s->code_ptr; + + /* TB epilogue */ + for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) { + tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i], + TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4); + } + + tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0); + tcg_out_addi(s, TCG_REG_SP, frame_size); +} + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff); + tcg_regset_set(tcg_target_call_clobber_regs, + (1 << TCG_REG_V0) | + (1 << TCG_REG_V1) | + (1 << TCG_REG_A0) | + (1 << TCG_REG_A1) | + (1 << TCG_REG_A2) | + (1 << TCG_REG_A3) | + (1 << TCG_REG_T1) | + (1 << TCG_REG_T2) | + (1 << TCG_REG_T3) | + (1 << TCG_REG_T4) | + (1 << TCG_REG_T5) | + (1 << TCG_REG_T6) | + (1 << TCG_REG_T7) | + (1 << TCG_REG_T8) | + (1 << TCG_REG_T9)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0); /* kernel use only */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1); /* kernel use only */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT); /* internal use */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0); /* internal use */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + + tcg_add_target_add_op_defs(mips_op_defs); +} diff --git a/qemu/qemu-git/tcg/mips/tcg-target.h b/qemu/qemu-git/tcg/mips/tcg-target.h new file mode 100644 index 0000000..46760a5 --- /dev/null +++ b/qemu/qemu-git/tcg/mips/tcg-target.h @@ -0,0 +1,104 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008-2009 Arnaud Patard + * Copyright (c) 2009 Aurelien Jarno + * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_MIPS 1 + +#define TCG_TARGET_REG_BITS 32 +#ifdef __MIPSEB__ +# define TCG_TARGET_WORDS_BIGENDIAN +#endif + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_ZERO = 0, + TCG_REG_AT, + TCG_REG_V0, + TCG_REG_V1, + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3, + TCG_REG_T0, + TCG_REG_T1, + TCG_REG_T2, + TCG_REG_T3, + TCG_REG_T4, + TCG_REG_T5, + TCG_REG_T6, + TCG_REG_T7, + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, + TCG_REG_S3, + TCG_REG_S4, + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, + TCG_REG_T8, + TCG_REG_T9, + TCG_REG_K0, + TCG_REG_K1, + TCG_REG_GP, + TCG_REG_SP, + TCG_REG_FP, + TCG_REG_RA, +}; + +#define TCG_CT_CONST_ZERO 0x100 +#define TCG_CT_CONST_U16 0x200 +#define TCG_CT_CONST_S16 0x400 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 16 +#define TCG_TARGET_CALL_ALIGN_ARGS 1 + +/* optional instructions */ +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_not_i32 +#undef TCG_TARGET_HAS_ext8s_i32 +#undef TCG_TARGET_HAS_ext16s_i32 +#undef TCG_TARGET_HAS_bswap32_i32 +#undef TCG_TARGET_HAS_bswap16_i32 +#undef TCG_TARGET_HAS_rot_i32 + +/* optional instructions automatically implemented */ +#undef TCG_TARGET_HAS_neg_i32 /* sub rd, zero, rt */ +#undef TCG_TARGET_HAS_ext8u_i32 /* andi rt, rs, 0xff */ +#undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */ + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_FP +#define TCG_AREG1 TCG_REG_S0 +#define TCG_AREG2 TCG_REG_S1 + +#include + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + cacheflush ((void *)start, stop-start, ICACHE); +} diff --git a/qemu/qemu-git/tcg/ppc/.svn/all-wcprops b/qemu/qemu-git/tcg/ppc/.svn/all-wcprops new file mode 100644 index 0000000..c11d654 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 47 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 60 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/ppc/.svn/entries b/qemu/qemu-git/tcg/ppc/.svn/entries new file mode 100644 index 0000000..4e89085 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/ppc +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +5d6bb229453943c26c91cd2499c4ad55 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +45330 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +d00ba062f95acc9883ce831e2e11f85d +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2482 + diff --git a/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..07e6941 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1615 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static uint8_t *tb_ret_addr; + +#ifdef __APPLE__ +#define LINKAGE_AREA_SIZE 24 +#define LR_OFFSET 8 +#elif defined _AIX +#define LINKAGE_AREA_SIZE 52 +#define LR_OFFSET 8 +#else +#define LINKAGE_AREA_SIZE 8 +#define LR_OFFSET 4 +#endif + +#define FAST_PATH +#if TARGET_PHYS_ADDR_BITS <= 32 +#define ADDEND_OFFSET 0 +#else +#define ADDEND_OFFSET 4 +#endif + +#ifndef GUEST_BASE +#define GUEST_BASE 0 +#endif + +#ifdef CONFIG_USE_GUEST_BASE +#define TCG_GUEST_BASE_REG 30 +#else +#define TCG_GUEST_BASE_REG 0 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, +#ifdef __APPLE__ + TCG_REG_R2, +#endif + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, +#ifndef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R12, +#ifndef __linux__ + TCG_REG_R13, +#endif + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3, + TCG_REG_R4 +}; + +static const int tcg_target_callee_save_regs[] = { +#ifdef __APPLE__ + TCG_REG_R11, + TCG_REG_R13, +#endif +#ifdef _AIX + TCG_REG_R13, +#endif + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + /* TCG_REG_R27, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 6) >> 6 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count(int flags) +{ + return ARRAY_SIZE (tcg_target_call_iarg_regs); +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; +#ifdef CONFIG_SOFTMMU + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + break; + case 'K': /* qemu_st[8..32] constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +#endif + break; + case 'M': /* qemu_st64 constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); + break; +#else + case 'L': + case 'K': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'M': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + break; +#endif + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO19(opc) (OPCD(19)|((opc)<<1)) + +#define B OPCD(18) +#define BC OPCD(16) +#define LBZ OPCD(34) +#define LHZ OPCD(40) +#define LHA OPCD(42) +#define LWZ OPCD(32) +#define STB OPCD(38) +#define STH OPCD(44) +#define STW OPCD(36) + +#define ADDI OPCD(14) +#define ADDIS OPCD(15) +#define ORI OPCD(24) +#define ORIS OPCD(25) +#define XORI OPCD(26) +#define XORIS OPCD(27) +#define ANDI OPCD(28) +#define ANDIS OPCD(29) +#define MULLI OPCD( 7) +#define CMPLI OPCD(10) +#define CMPI OPCD(11) + +#define LWZU OPCD(33) +#define STWU OPCD(37) + +#define RLWINM OPCD(21) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define LBZX XO31( 87) +#define LHZX XO31(279) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define TW XO31(4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO (4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 6) >> 6 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) +{ +#ifdef _AIX + int reg; + + if (const_arg) { + reg = 2; + tcg_out_movi (s, TCG_TYPE_I32, reg, arg); + } + else reg = arg; + + tcg_out32 (s, LWZ | RT (0) | RA (reg)); + tcg_out32 (s, MTSPR | RA (0) | CTR); + tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4); + tcg_out32 (s, BCCTR | BO_ALWAYS | LK); +#else + if (const_arg) { + tcg_out_b (s, LK, arg); + } + else { + tcg_out32 (s, MTSPR | RS (arg) | LR); + tcg_out32 (s, BCLR | BO_ALWAYS | LK); + } +#endif +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, rbase, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_read) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index); +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); +#endif + + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + case 3: + if (data_reg == 3) { + if (data_reg2 == 4) { + tcg_out_mov (s, 0, 4); + tcg_out_mov (s, 4, 3); + tcg_out_mov (s, 3, 0); + } + else { + tcg_out_mov (s, data_reg2, 3); + tcg_out_mov (s, 3, 4); + } + } + else { + if (data_reg != 4) tcg_out_mov (s, data_reg, 4); + if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3); + } + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + break; + case 0|4: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, LWBRX | TAB (data_reg2, rbase, r1)); + } + else { +#ifdef CONFIG_USE_GUEST_BASE + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWZX | TAB (data_reg2, rbase, r0)); + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r1)); +#else + if (r0 == data_reg2) { + tcg_out32 (s, LWZ | RT (0) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + tcg_out_mov (s, data_reg2, 0); + } + else { + tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + } +#endif + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap, rbase; +#ifdef CONFIG_SOFTMMU + int r2, ir; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_write) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - opc) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + ir = 4; +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#else + ir = 4; +#endif +#endif + + switch (opc) { + case 0: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (24) + | ME (31))); + break; + case 1: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (16) + | ME (31))); + break; + case 2: + tcg_out_mov (s, ir, data_reg); + break; + case 3: +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#endif + tcg_out_mov (s, ir++, data_reg2); + tcg_out_mov (s, ir, data_reg); + break; + } + ir++; + + tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); + tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STBX | SAB (data_reg, rbase, r0)); + break; + case 1: + if (bswap) + tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STHX | SAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STWX | SAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + tcg_out32 (s, STWBRX | SAB (data_reg2, rbase, r1)); + } + else { +#ifdef CONFIG_USE_GUEST_BASE + tcg_out32 (s, STWX | SAB (data_reg2, rbase, r0)); + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, STWX | SAB (data_reg, rbase, r1)); +#else + tcg_out32 (s, STW | RS (data_reg2) | RA (r0)); + tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4); +#endif + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; + + frame_size = 0 + + LINKAGE_AREA_SIZE + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 4 + ; + frame_size = (frame_size + 15) & ~15; + +#ifdef _AIX + { + uint32_t addr; + + /* First emit adhoc function descriptor */ + addr = (uint32_t) s->code_ptr + 12; + tcg_out32 (s, addr); /* entry point */ + s->code_ptr += 8; /* skip TOC and environment pointer */ + } +#endif + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STW + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET)); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_out_movi (s, TCG_TYPE_I32, TCG_GUEST_BASE_REG, GUEST_BASE); +#endif + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LWZ + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); +} + +static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I32, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, + const int *const_args) +{ + int cond = args[4], label_index = args[5], op; + struct { int bit1; int bit2; int cond2; } bits[] = { + [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT }, + [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT }, + [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT }, + [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT }, + [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU }, + [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU }, + [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU }, + [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU }, + }, *b = &bits[cond]; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + op = (cond == TCG_COND_EQ) ? CRAND : CRNAND; + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6); + tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); + break; + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_GT: + case TCG_COND_GE: + case TCG_COND_LTU: + case TCG_COND_LEU: + case TCG_COND_GTU: + case TCG_COND_GEU: + op = (b->bit1 != b->bit2) ? CRANDC : CRAND; + tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5); + tcg_out_cmp (s, TCG_COND_EQ, args[1], args[3], const_args[3], 6); + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, b->bit2)); + tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ)); + break; + default: + tcg_abort(); + } + + tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + uint32_t *ptr; + long disp = addr - jmp_addr; + unsigned long patch_size; + + ptr = (uint32_t *)jmp_addr; + + if ((disp << 6) >> 6 != disp) { + ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */ + ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */ + ptr[2] = 0x7c0903a6; /* mtctr 0 */ + ptr[3] = 0x4e800420; /* brctr */ + patch_size = 16; + } else { + /* patch the branch destination */ + if (disp != 16) { + *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */ + patch_size = 4; + } else { + ptr[0] = 0x60000000; /* nop */ + ptr[1] = 0x60000000; + ptr[2] = 0x60000000; + ptr[3] = 0x60000000; + patch_size = 16; + } + } + /* flush icache */ + flush_icache_range(jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 16; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + tcg_out_call (s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_st8_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i32: + if (const_args[2]) { + uint32_t c; + + c = args[2]; + + if (!c) { + tcg_out_movi (s, TCG_TYPE_I32, args[0], 0); + break; + } +#ifdef __PPU__ + uint32_t t, n; + int mb, me; + + n = c ^ -(c & 1); + t = n + (n & -n); + + if ((t & (t - 1)) == 0) { + int lzc, tzc; + + if ((c & 0x80000001) == 0x80000001) { + lzc = clz32 (n); + tzc = ctz32 (n); + + mb = 32 - tzc; + me = lzc - 1; + } + else { + lzc = clz32 (c); + tzc = ctz32 (c); + + mb = lzc; + me = 31 - tzc; + } + + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (0) + | MB (mb) + | ME (me) + ) + ); + } + else +#endif /* !__PPU__ */ + { + if ((c & 0xffff) == c) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | c); + else if ((c & 0xffff0000) == c) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((c >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, c); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_mulu2_i32: + if (args[0] == args[2] || args[0] == args[3]) { + tcg_out32 (s, MULLW | TAB (0, args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + } + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_add2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, ADDC | TAB (0, args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + } + break; + case INDEX_op_sub2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, SUBFC | TAB (0, args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + } + break; + + case INDEX_op_brcond_i32: + /* + args[0] = r0 + args[1] = r1 + args[2] = cond + args[3] = r1 is const + args[4] = label_index + */ + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_neg_i32: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + case INDEX_op_ext8s_i32: + tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0])); + break; + case INDEX_op_ext16s_i32: + tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M", "M" } }, +#endif + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | +#ifdef __APPLE__ + (1 << TCG_REG_R2) | +#endif + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); +#ifndef __APPLE__ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); +#endif +#ifdef __linux__ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); +#endif +#ifdef CONFIG_USE_GUEST_BASE + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); +#endif + + tcg_add_target_add_op_defs(ppc_op_defs); +} diff --git a/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..0197e79 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,89 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_PPC 1 + +#define TCG_TARGET_REG_BITS 32 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#if defined __APPLE__ +#define TCG_TARGET_CALL_STACK_OFFSET 24 +#elif defined _AIX +#define TCG_TARGET_CALL_STACK_OFFSET 52 +#elif defined __linux__ +#define TCG_TARGET_CALL_ALIGN_ARGS 1 +#define TCG_TARGET_CALL_STACK_OFFSET 8 +#else +#error Unsupported system +#endif + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 + +#define TCG_TARGET_HAS_GUEST_BASE diff --git a/qemu/qemu-git/tcg/ppc/tcg-target.c b/qemu/qemu-git/tcg/ppc/tcg-target.c new file mode 100644 index 0000000..07e6941 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/tcg-target.c @@ -0,0 +1,1615 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static uint8_t *tb_ret_addr; + +#ifdef __APPLE__ +#define LINKAGE_AREA_SIZE 24 +#define LR_OFFSET 8 +#elif defined _AIX +#define LINKAGE_AREA_SIZE 52 +#define LR_OFFSET 8 +#else +#define LINKAGE_AREA_SIZE 8 +#define LR_OFFSET 4 +#endif + +#define FAST_PATH +#if TARGET_PHYS_ADDR_BITS <= 32 +#define ADDEND_OFFSET 0 +#else +#define ADDEND_OFFSET 4 +#endif + +#ifndef GUEST_BASE +#define GUEST_BASE 0 +#endif + +#ifdef CONFIG_USE_GUEST_BASE +#define TCG_GUEST_BASE_REG 30 +#else +#define TCG_GUEST_BASE_REG 0 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, +#ifdef __APPLE__ + TCG_REG_R2, +#endif + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, +#ifndef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R12, +#ifndef __linux__ + TCG_REG_R13, +#endif + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3, + TCG_REG_R4 +}; + +static const int tcg_target_callee_save_regs[] = { +#ifdef __APPLE__ + TCG_REG_R11, + TCG_REG_R13, +#endif +#ifdef _AIX + TCG_REG_R13, +#endif + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + /* TCG_REG_R27, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 6) >> 6 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count(int flags) +{ + return ARRAY_SIZE (tcg_target_call_iarg_regs); +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; +#ifdef CONFIG_SOFTMMU + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + break; + case 'K': /* qemu_st[8..32] constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +#endif + break; + case 'M': /* qemu_st64 constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); + break; +#else + case 'L': + case 'K': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'M': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + break; +#endif + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO19(opc) (OPCD(19)|((opc)<<1)) + +#define B OPCD(18) +#define BC OPCD(16) +#define LBZ OPCD(34) +#define LHZ OPCD(40) +#define LHA OPCD(42) +#define LWZ OPCD(32) +#define STB OPCD(38) +#define STH OPCD(44) +#define STW OPCD(36) + +#define ADDI OPCD(14) +#define ADDIS OPCD(15) +#define ORI OPCD(24) +#define ORIS OPCD(25) +#define XORI OPCD(26) +#define XORIS OPCD(27) +#define ANDI OPCD(28) +#define ANDIS OPCD(29) +#define MULLI OPCD( 7) +#define CMPLI OPCD(10) +#define CMPI OPCD(11) + +#define LWZU OPCD(33) +#define STWU OPCD(37) + +#define RLWINM OPCD(21) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define LBZX XO31( 87) +#define LHZX XO31(279) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define TW XO31(4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO (4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 6) >> 6 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) +{ +#ifdef _AIX + int reg; + + if (const_arg) { + reg = 2; + tcg_out_movi (s, TCG_TYPE_I32, reg, arg); + } + else reg = arg; + + tcg_out32 (s, LWZ | RT (0) | RA (reg)); + tcg_out32 (s, MTSPR | RA (0) | CTR); + tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4); + tcg_out32 (s, BCCTR | BO_ALWAYS | LK); +#else + if (const_arg) { + tcg_out_b (s, LK, arg); + } + else { + tcg_out32 (s, MTSPR | RS (arg) | LR); + tcg_out32 (s, BCLR | BO_ALWAYS | LK); + } +#endif +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, data_reg2, r0, r1, rbase, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_read) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index); +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); + tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); +#endif + + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + case 3: + if (data_reg == 3) { + if (data_reg2 == 4) { + tcg_out_mov (s, 0, 4); + tcg_out_mov (s, 4, 3); + tcg_out_mov (s, 3, 0); + } + else { + tcg_out_mov (s, data_reg2, 3); + tcg_out_mov (s, 3, 4); + } + } + else { + if (data_reg != 4) tcg_out_mov (s, data_reg, 4); + if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3); + } + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + break; + case 0|4: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, LWBRX | TAB (data_reg2, rbase, r1)); + } + else { +#ifdef CONFIG_USE_GUEST_BASE + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWZX | TAB (data_reg2, rbase, r0)); + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r1)); +#else + if (r0 == data_reg2) { + tcg_out32 (s, LWZ | RT (0) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + tcg_out_mov (s, data_reg2, 0); + } + else { + tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0)); + tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); + } +#endif + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap, rbase; +#ifdef CONFIG_SOFTMMU + int r2, ir; + void *label1_ptr, *label2_ptr; +#endif +#if TARGET_LONG_BITS == 64 + int addr_reg2; +#endif + + data_reg = *args++; + if (opc == 3) + data_reg2 = *args++; + else + data_reg2 = 0; + addr_reg = *args++; +#if TARGET_LONG_BITS == 64 + addr_reg2 = *args++; +#endif + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU + | RT (r1) + | RA (r0) + | offsetof (CPUState, tlb_table[mem_index][0].addr_write) + ) + ); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - opc) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); + + tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1)); +#if TARGET_LONG_BITS == 64 + tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); + tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); + tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); +#endif + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ +#if TARGET_LONG_BITS == 32 + tcg_out_mov (s, 3, addr_reg); + ir = 4; +#else + tcg_out_mov (s, 3, addr_reg2); + tcg_out_mov (s, 4, addr_reg); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#else + ir = 4; +#endif +#endif + + switch (opc) { + case 0: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (24) + | ME (31))); + break; + case 1: + tcg_out32 (s, (RLWINM + | RA (ir) + | RS (data_reg) + | SH (0) + | MB (16) + | ME (31))); + break; + case 2: + tcg_out_mov (s, ir, data_reg); + break; + case 3: +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir = 5; +#endif + tcg_out_mov (s, ir++, data_reg2); + tcg_out_mov (s, ir, data_reg); + break; + } + ir++; + + tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); + tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LWZ + | RT (r0) + | RA (r0) + | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STBX | SAB (data_reg, rbase, r0)); + break; + case 1: + if (bswap) + tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STHX | SAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STWX | SAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + tcg_out32 (s, STWBRX | SAB (data_reg2, rbase, r1)); + } + else { +#ifdef CONFIG_USE_GUEST_BASE + tcg_out32 (s, STWX | SAB (data_reg2, rbase, r0)); + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, STWX | SAB (data_reg, rbase, r1)); +#else + tcg_out32 (s, STW | RS (data_reg2) | RA (r0)); + tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4); +#endif + } + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; + + frame_size = 0 + + LINKAGE_AREA_SIZE + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 4 + ; + frame_size = (frame_size + 15) & ~15; + +#ifdef _AIX + { + uint32_t addr; + + /* First emit adhoc function descriptor */ + addr = (uint32_t) s->code_ptr + 12; + tcg_out32 (s, addr); /* entry point */ + s->code_ptr += 8; /* skip TOC and environment pointer */ + } +#endif + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STW + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET)); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_out_movi (s, TCG_TYPE_I32, TCG_GUEST_BASE_REG, GUEST_BASE); +#endif + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LWZ + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); +} + +static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I32, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, + const int *const_args) +{ + int cond = args[4], label_index = args[5], op; + struct { int bit1; int bit2; int cond2; } bits[] = { + [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT }, + [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT }, + [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT }, + [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT }, + [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU }, + [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU }, + [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU }, + [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU }, + }, *b = &bits[cond]; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + op = (cond == TCG_COND_EQ) ? CRAND : CRNAND; + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6); + tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); + break; + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_GT: + case TCG_COND_GE: + case TCG_COND_LTU: + case TCG_COND_LEU: + case TCG_COND_GTU: + case TCG_COND_GEU: + op = (b->bit1 != b->bit2) ? CRANDC : CRAND; + tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5); + tcg_out_cmp (s, TCG_COND_EQ, args[1], args[3], const_args[3], 6); + tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 7); + tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, b->bit2)); + tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ)); + break; + default: + tcg_abort(); + } + + tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + uint32_t *ptr; + long disp = addr - jmp_addr; + unsigned long patch_size; + + ptr = (uint32_t *)jmp_addr; + + if ((disp << 6) >> 6 != disp) { + ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */ + ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */ + ptr[2] = 0x7c0903a6; /* mtctr 0 */ + ptr[3] = 0x4e800420; /* brctr */ + patch_size = 16; + } else { + /* patch the branch destination */ + if (disp != 16) { + *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */ + patch_size = 4; + } else { + ptr[0] = 0x60000000; /* nop */ + ptr[1] = 0x60000000; + ptr[2] = 0x60000000; + ptr[3] = 0x60000000; + patch_size = 16; + } + } + /* flush icache */ + flush_icache_range(jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 16; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + tcg_out_call (s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_st8_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i32: + if (const_args[2]) { + uint32_t c; + + c = args[2]; + + if (!c) { + tcg_out_movi (s, TCG_TYPE_I32, args[0], 0); + break; + } +#ifdef __PPU__ + uint32_t t, n; + int mb, me; + + n = c ^ -(c & 1); + t = n + (n & -n); + + if ((t & (t - 1)) == 0) { + int lzc, tzc; + + if ((c & 0x80000001) == 0x80000001) { + lzc = clz32 (n); + tzc = ctz32 (n); + + mb = 32 - tzc; + me = lzc - 1; + } + else { + lzc = clz32 (c); + tzc = ctz32 (c); + + mb = lzc; + me = 31 - tzc; + } + + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (0) + | MB (mb) + | ME (me) + ) + ); + } + else +#endif /* !__PPU__ */ + { + if ((c & 0xffff) == c) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | c); + else if ((c & 0xffff0000) == c) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((c >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, c); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_mulu2_i32: + if (args[0] == args[2] || args[0] == args[3]) { + tcg_out32 (s, MULLW | TAB (0, args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3])); + tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); + } + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_add2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, ADDC | TAB (0, args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4])); + tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); + } + break; + case INDEX_op_sub2_i32: + if (args[0] == args[3] || args[0] == args[5]) { + tcg_out32 (s, SUBFC | TAB (0, args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + tcg_out_mov (s, args[0], 0); + } + else { + tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2])); + tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); + } + break; + + case INDEX_op_brcond_i32: + /* + args[0] = r0 + args[1] = r1 + args[2] = cond + args[3] = r1 is const + args[4] = label_index + */ + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]); + break; + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args); + break; + + case INDEX_op_neg_i32: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + case INDEX_op_ext8s_i32: + tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0])); + break; + case INDEX_op_ext16s_i32: + tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, + { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + +#if TARGET_LONG_BITS == 32 + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "r", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M" } }, +#else + { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } }, + + { INDEX_op_qemu_st8, { "K", "K", "K" } }, + { INDEX_op_qemu_st16, { "K", "K", "K" } }, + { INDEX_op_qemu_st32, { "K", "K", "K" } }, + { INDEX_op_qemu_st64, { "M", "M", "M", "M" } }, +#endif + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | +#ifdef __APPLE__ + (1 << TCG_REG_R2) | +#endif + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); +#ifndef __APPLE__ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); +#endif +#ifdef __linux__ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); +#endif +#ifdef CONFIG_USE_GUEST_BASE + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); +#endif + + tcg_add_target_add_op_defs(ppc_op_defs); +} diff --git a/qemu/qemu-git/tcg/ppc/tcg-target.h b/qemu/qemu-git/tcg/ppc/tcg-target.h new file mode 100644 index 0000000..0197e79 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc/tcg-target.h @@ -0,0 +1,89 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_PPC 1 + +#define TCG_TARGET_REG_BITS 32 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#if defined __APPLE__ +#define TCG_TARGET_CALL_STACK_OFFSET 24 +#elif defined _AIX +#define TCG_TARGET_CALL_STACK_OFFSET 52 +#elif defined __linux__ +#define TCG_TARGET_CALL_ALIGN_ARGS 1 +#define TCG_TARGET_CALL_STACK_OFFSET 8 +#else +#error Unsupported system +#endif + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 + +#define TCG_TARGET_HAS_GUEST_BASE diff --git a/qemu/qemu-git/tcg/ppc64/.svn/all-wcprops b/qemu/qemu-git/tcg/ppc64/.svn/all-wcprops new file mode 100644 index 0000000..283c770 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc64 +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc64/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/ppc64/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/ppc64/.svn/entries b/qemu/qemu-git/tcg/ppc64/.svn/entries new file mode 100644 index 0000000..d5aae10 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/ppc64 +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +89a4d5db0bf452bffd14e2d50214d6b6 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +44198 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +0e7b6224bdda2c765280c10fdb2372a1 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2427 + diff --git a/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..803db48 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1570 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define TCG_CT_CONST_U32 0x100 + +static uint8_t *tb_ret_addr; + +#define FAST_PATH + +#if TARGET_PHYS_ADDR_BITS == 32 +#define LD_ADDEND LWZ +#else +#define LD_ADDEND LD +#endif + +#if TARGET_LONG_BITS == 32 +#define LD_ADDR LWZU +#define CMP_L 0 +#else +#define LD_ADDR LDU +#define CMP_L (1<<21) +#endif + +#ifndef GUEST_BASE +#define GUEST_BASE 0 +#endif + +#ifdef CONFIG_USE_GUEST_BASE +#define TCG_GUEST_BASE_REG 30 +#else +#define TCG_GUEST_BASE_REG 0 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, +#ifdef __APPLE__ + TCG_REG_R2, +#endif + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, +#ifndef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R12, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3 +}; + +static const int tcg_target_callee_save_regs[] = { +#ifdef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + /* TCG_REG_R27, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 38) >> 38 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc (uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort (); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count (int flags) +{ + return ARRAY_SIZE (tcg_target_call_iarg_regs); +} + +/* parse target specific constraints */ +static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); +#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5); +#endif + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match (tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_U32) && (val == (uint32_t) val)) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO19(opc) (OPCD(19)|((opc)<<1)) +#define XO30(opc) (OPCD(30)|((opc)<<2)) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO58(opc) (OPCD(58)|(opc)) +#define XO62(opc) (OPCD(62)|(opc)) + +#define B OPCD( 18) +#define BC OPCD( 16) +#define LBZ OPCD( 34) +#define LHZ OPCD( 40) +#define LHA OPCD( 42) +#define LWZ OPCD( 32) +#define STB OPCD( 38) +#define STH OPCD( 44) +#define STW OPCD( 36) + +#define STD XO62( 0) +#define STDU XO62( 1) +#define STDX XO31(149) + +#define LD XO58( 0) +#define LDX XO31( 21) +#define LDU XO58( 1) +#define LWA XO58( 2) +#define LWAX XO31(341) + +#define ADDI OPCD( 14) +#define ADDIS OPCD( 15) +#define ORI OPCD( 24) +#define ORIS OPCD( 25) +#define XORI OPCD( 26) +#define XORIS OPCD( 27) +#define ANDI OPCD( 28) +#define ANDIS OPCD( 29) +#define MULLI OPCD( 7) +#define CMPLI OPCD( 10) +#define CMPI OPCD( 11) + +#define LWZU OPCD( 33) +#define STWU OPCD( 37) + +#define RLWINM OPCD( 21) + +#define RLDICL XO30( 0) +#define RLDICR XO30( 1) +#define RLDIMI XO30( 3) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define EXTSW XO31(986) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define MULLD XO31(233) +#define MULHD XO31( 73) +#define MULHDU XO31( 9) +#define DIVD XO31(489) +#define DIVDU XO31(457) + +#define LBZX XO31( 87) +#define LHZX XO31(279) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define SLD XO31( 27) +#define SRD XO31(539) +#define SRAD XO31(794) +#define SRADI XO31(413<<1) + +#define TW XO31( 4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) +#define MB64(b) ((b)<<5) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO ( 4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov (TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_rld (TCGContext *s, int op, int ra, int rs, int sh, int mb) +{ + sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1); + mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f)); + tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb); +} + +static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_movi (TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + int32_t arg32 = arg; + arg = type == TCG_TYPE_I32 ? arg & 0xffffffff : arg; + + if (arg == arg32) { + tcg_out_movi32 (s, ret, arg32); + } + else { + if ((uint64_t) arg >> 32) { + uint16_t h16 = arg >> 16; + uint16_t l16 = arg; + + tcg_out_movi32 (s, ret, arg >> 32); + tcg_out_rld (s, RLDICR, ret, ret, 32, 31); + if (h16) tcg_out32 (s, ORIS | RS (ret) | RA (ret) | h16); + if (l16) tcg_out32 (s, ORI | RS (ret) | RA (ret) | l16); + } + else { + tcg_out_movi32 (s, ret, arg32); + if (arg32 < 0) + tcg_out_rld (s, RLDICL, ret, ret, 0, 32); + } + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 38) >> 38 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) +{ +#ifdef __APPLE__ + if (const_arg) { + tcg_out_b (s, LK, arg); + } + else { + tcg_out32 (s, MTSPR | RS (arg) | LR); + tcg_out32 (s, BCLR | BO_ALWAYS | LK); + } +#else + int reg; + + if (const_arg) { + reg = 2; + tcg_out_movi (s, TCG_TYPE_I64, reg, arg); + } + else reg = arg; + + tcg_out32 (s, LD | RT (0) | RA (reg)); + tcg_out32 (s, MTSPR | RA (0) | CTR); + tcg_out32 (s, LD | RT (11) | RA (reg) | 16); + tcg_out32 (s, LD | RT (2) | RA (reg) | 8); + tcg_out32 (s, BCCTR | BO_ALWAYS | LK); +#endif +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_ldsta (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) (offset & ~3)) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +#if defined (CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; + +static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, + int addr_reg, int s_bits, int offset) +{ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU | RT (r1) | RA (r0) | offset)); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); +#else + tcg_out_rld (s, RLDICL, r0, addr_reg, + 64 - TARGET_PAGE_BITS, + 64 - CPU_TLB_BITS); + tcg_out_rld (s, RLDICR, r0, r0, + CPU_TLB_ENTRY_BITS, + 63 - CPU_TLB_ENTRY_BITS); + + tcg_out32 (s, ADD | TAB (r0, r0, TCG_AREG0)); + tcg_out32 (s, LD_ADDR | RT (r1) | RA (r0) | offset); + + if (!s_bits) { + tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS); + } + else { + tcg_out_rld (s, RLDICL, r2, addr_reg, + 64 - TARGET_PAGE_BITS, + TARGET_PAGE_BITS - s_bits); + tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0); + } +#endif +} +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits, + offsetof (CPUState, tlb_table[mem_index][0].addr_read)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); + + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 2|4: + tcg_out32 (s, EXTSW | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + case 3: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + break; + case 0|4: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0)); + break; + case 2|4: + if (bswap) { + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSW | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LWAX | TAB (data_reg, rbase, r0)); + break; + case 3: +#ifdef CONFIG_USE_GUEST_BASE + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, LWBRX | TAB ( r1, rbase, r1)); + tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0); + } + else tcg_out32 (s, LDX | TAB (data_reg, rbase, r0)); +#else + if (bswap) { + tcg_out_movi32 (s, 0, 4); + tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, LWBRX | RT ( r1) | RA (r0)); + tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0); + } + else tcg_out32 (s, LD | RT (data_reg) | RA (r0)); +#endif + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc, + offsetof (CPUState, tlb_table[mem_index][0].addr_write)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc))); + tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); + + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r1 = 3; + r0 = addr_reg; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STBX | SAB (data_reg, rbase, r0)); + break; + case 1: + if (bswap) + tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STHX | SAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STWX | SAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out_rld (s, RLDICL, 0, data_reg, 32, 0); + tcg_out32 (s, STWBRX | SAB (0, rbase, r1)); + } + else tcg_out32 (s, STDX | SAB (data_reg, rbase, r0)); + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; +#ifndef __APPLE__ + uint64_t addr; +#endif + + frame_size = 0 + + 8 /* back chain */ + + 8 /* CR */ + + 8 /* LR */ + + 8 /* compiler doubleword */ + + 8 /* link editor doubleword */ + + 8 /* TOC save area */ + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 8 + ; + frame_size = (frame_size + 15) & ~15; + +#ifndef __APPLE__ + /* First emit adhoc function descriptor */ + addr = (uint64_t) s->code_ptr + 24; + tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */ + s->code_ptr += 16; /* skip TOC and environment pointer */ +#endif + + /* Prologue */ + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STD + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16)); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_out_movi (s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE); +#endif + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + + /* Epilogue */ + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LD + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LD | RT (0) | RA (1) | (frame_size + 16)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); + else + tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); + else + tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX); +} + +static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + /* XXX: suboptimal */ + if (si == (int16_t) si + || ((((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0)) + ppc_addi32 (s, rt, ra, si); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, si); + tcg_out32 (s, ADD | RT (rt) | RA (ra)); + } +} + +static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi64 (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr, int arch64) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr) | (arch64 << 21); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I64, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int arch64) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, arch64); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + TCGContext s; + unsigned long patch_size; + + s.code_ptr = (uint8_t *) jmp_addr; + tcg_out_b (&s, 0, addr); + patch_size = s.code_ptr - (uint8_t *) jmp_addr; + flush_icache_range (jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op (TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 28; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + tcg_out_call (s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX); + break; + case INDEX_op_ld_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX); + break; + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + case INDEX_op_st_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i64: + case INDEX_op_and_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i64: + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i64: + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 0); + break; + + case INDEX_op_brcond_i64: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 1); + break; + + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_add_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_shl_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICR, args[0], args[1], args[2], 63 - args[2]); + else + tcg_out32 (s, SLD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICL, args[0], args[1], 64 - args[2], args[2]); + else + tcg_out32 (s, SRD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i64: + if (const_args[2]) { + int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1); + tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh); + } + else + tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i64: + tcg_out32 (s, MULLD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_div_i64: + tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_divu_i64: + tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_rem_i64: + tcg_out32 (s, DIVD | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + case INDEX_op_remu_i64: + tcg_out32 (s, DIVDU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld (s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld (s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld (s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld (s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld (s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld (s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld (s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st (s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st (s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st (s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st (s, args, 3); + break; + + case INDEX_op_ext8s_i32: + case INDEX_op_ext8s_i64: + c = EXTSB; + goto gen_ext; + case INDEX_op_ext16s_i32: + case INDEX_op_ext16s_i64: + c = EXTSH; + goto gen_ext; + case INDEX_op_ext32s_i64: + c = EXTSW; + goto gen_ext; + gen_ext: + tcg_out32 (s, c | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_movi_i64, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + { INDEX_op_brcond_i64, { "r", "ri" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "r", "ri" } }, + { INDEX_op_sub_i64, { "r", "r", "ri" } }, + { INDEX_op_and_i64, { "r", "r", "rZ" } }, + { INDEX_op_or_i64, { "r", "r", "rZ" } }, + { INDEX_op_xor_i64, { "r", "r", "rZ" } }, + + { INDEX_op_shl_i64, { "r", "r", "ri" } }, + { INDEX_op_shr_i64, { "r", "r", "ri" } }, + { INDEX_op_sar_i64, { "r", "r", "ri" } }, + + { INDEX_op_mul_i64, { "r", "r", "r" } }, + { INDEX_op_div_i64, { "r", "r", "r" } }, + { INDEX_op_divu_i64, { "r", "r", "r" } }, + { INDEX_op_rem_i64, { "r", "r", "r" } }, + { INDEX_op_remu_i64, { "r", "r", "r" } }, + + { INDEX_op_neg_i64, { "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "S", "S" } }, + { INDEX_op_qemu_st16, { "S", "S" } }, + { INDEX_op_qemu_st32, { "S", "S" } }, + { INDEX_op_qemu_st64, { "S", "S" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8s_i64, { "r", "r" } }, + { INDEX_op_ext16s_i64, { "r", "r" } }, + { INDEX_op_ext32s_i64, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init (TCGContext *s) +{ + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | +#ifdef __APPLE__ + (1 << TCG_REG_R2) | +#endif + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear (s->reserved_regs); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1); +#ifndef __APPLE__ + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2); +#endif + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); +#endif + + tcg_add_target_add_op_defs (ppc_op_defs); +} diff --git a/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..94b800f --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,85 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_PPC64 1 + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 48 + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_div_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 + +#define TCG_TARGET_HAS_GUEST_BASE diff --git a/qemu/qemu-git/tcg/ppc64/tcg-target.c b/qemu/qemu-git/tcg/ppc64/tcg-target.c new file mode 100644 index 0000000..803db48 --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/tcg-target.c @@ -0,0 +1,1570 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define TCG_CT_CONST_U32 0x100 + +static uint8_t *tb_ret_addr; + +#define FAST_PATH + +#if TARGET_PHYS_ADDR_BITS == 32 +#define LD_ADDEND LWZ +#else +#define LD_ADDEND LD +#endif + +#if TARGET_LONG_BITS == 32 +#define LD_ADDR LWZU +#define CMP_L 0 +#else +#define LD_ADDR LDU +#define CMP_L (1<<21) +#endif + +#ifndef GUEST_BASE +#define GUEST_BASE 0 +#endif + +#ifdef CONFIG_USE_GUEST_BASE +#define TCG_GUEST_BASE_REG 30 +#else +#define TCG_GUEST_BASE_REG 0 +#endif + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "rp", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "r19", + "r20", + "r21", + "r22", + "r23", + "r24", + "r25", + "r26", + "r27", + "r28", + "r29", + "r30", + "r31" +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31, +#ifdef __APPLE__ + TCG_REG_R2, +#endif + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, +#ifndef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R12, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27 +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10 +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R3 +}; + +static const int tcg_target_callee_save_regs[] = { +#ifdef __APPLE__ + TCG_REG_R11, +#endif + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + /* TCG_REG_R27, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 38) >> 38 != disp) + tcg_abort (); + + return disp & 0x3fffffc; +} + +static void reloc_pc24 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) + | reloc_pc24_val (pc, target); +} + +static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; +} + +static void reloc_pc14 (void *pc, tcg_target_long target) +{ + *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) + | reloc_pc14_val (pc, target); +} + +static void patch_reloc (uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_PPC_REL14: + reloc_pc14 (code_ptr, value); + break; + case R_PPC_REL24: + reloc_pc24 (code_ptr, value); + break; + default: + tcg_abort (); + } +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count (int flags) +{ + return ARRAY_SIZE (tcg_target_call_iarg_regs); +} + +/* parse target specific constraints */ +static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'A': case 'B': case 'C': case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A'); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); +#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32 (ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); +#ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5); +#endif + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match (tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_U32) && (val == (uint32_t) val)) + return 1; + return 0; +} + +#define OPCD(opc) ((opc)<<26) +#define XO19(opc) (OPCD(19)|((opc)<<1)) +#define XO30(opc) (OPCD(30)|((opc)<<2)) +#define XO31(opc) (OPCD(31)|((opc)<<1)) +#define XO58(opc) (OPCD(58)|(opc)) +#define XO62(opc) (OPCD(62)|(opc)) + +#define B OPCD( 18) +#define BC OPCD( 16) +#define LBZ OPCD( 34) +#define LHZ OPCD( 40) +#define LHA OPCD( 42) +#define LWZ OPCD( 32) +#define STB OPCD( 38) +#define STH OPCD( 44) +#define STW OPCD( 36) + +#define STD XO62( 0) +#define STDU XO62( 1) +#define STDX XO31(149) + +#define LD XO58( 0) +#define LDX XO31( 21) +#define LDU XO58( 1) +#define LWA XO58( 2) +#define LWAX XO31(341) + +#define ADDI OPCD( 14) +#define ADDIS OPCD( 15) +#define ORI OPCD( 24) +#define ORIS OPCD( 25) +#define XORI OPCD( 26) +#define XORIS OPCD( 27) +#define ANDI OPCD( 28) +#define ANDIS OPCD( 29) +#define MULLI OPCD( 7) +#define CMPLI OPCD( 10) +#define CMPI OPCD( 11) + +#define LWZU OPCD( 33) +#define STWU OPCD( 37) + +#define RLWINM OPCD( 21) + +#define RLDICL XO30( 0) +#define RLDICR XO30( 1) +#define RLDIMI XO30( 3) + +#define BCLR XO19( 16) +#define BCCTR XO19(528) +#define CRAND XO19(257) +#define CRANDC XO19(129) +#define CRNAND XO19(225) +#define CROR XO19(449) + +#define EXTSB XO31(954) +#define EXTSH XO31(922) +#define EXTSW XO31(986) +#define ADD XO31(266) +#define ADDE XO31(138) +#define ADDC XO31( 10) +#define AND XO31( 28) +#define SUBF XO31( 40) +#define SUBFC XO31( 8) +#define SUBFE XO31(136) +#define OR XO31(444) +#define XOR XO31(316) +#define MULLW XO31(235) +#define MULHWU XO31( 11) +#define DIVW XO31(491) +#define DIVWU XO31(459) +#define CMP XO31( 0) +#define CMPL XO31( 32) +#define LHBRX XO31(790) +#define LWBRX XO31(534) +#define STHBRX XO31(918) +#define STWBRX XO31(662) +#define MFSPR XO31(339) +#define MTSPR XO31(467) +#define SRAWI XO31(824) +#define NEG XO31(104) + +#define MULLD XO31(233) +#define MULHD XO31( 73) +#define MULHDU XO31( 9) +#define DIVD XO31(489) +#define DIVDU XO31(457) + +#define LBZX XO31( 87) +#define LHZX XO31(279) +#define LHAX XO31(343) +#define LWZX XO31( 23) +#define STBX XO31(215) +#define STHX XO31(407) +#define STWX XO31(151) + +#define SPR(a,b) ((((a)<<5)|(b))<<11) +#define LR SPR(8, 0) +#define CTR SPR(9, 0) + +#define SLW XO31( 24) +#define SRW XO31(536) +#define SRAW XO31(792) + +#define SLD XO31( 27) +#define SRD XO31(539) +#define SRAD XO31(794) +#define SRADI XO31(413<<1) + +#define TW XO31( 4) +#define TRAP (TW | TO (31)) + +#define RT(r) ((r)<<21) +#define RS(r) ((r)<<21) +#define RA(r) ((r)<<16) +#define RB(r) ((r)<<11) +#define TO(t) ((t)<<21) +#define SH(s) ((s)<<11) +#define MB(b) ((b)<<6) +#define ME(e) ((e)<<1) +#define BO(o) ((o)<<21) +#define MB64(b) ((b)<<5) + +#define LK 1 + +#define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) +#define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) + +#define BF(n) ((n)<<23) +#define BI(n, c) (((c)+((n)*4))<<16) +#define BT(n, c) (((c)+((n)*4))<<21) +#define BA(n, c) (((c)+((n)*4))<<16) +#define BB(n, c) (((c)+((n)*4))<<11) + +#define BO_COND_TRUE BO (12) +#define BO_COND_FALSE BO ( 4) +#define BO_ALWAYS BO (20) + +enum { + CR_LT, + CR_GT, + CR_EQ, + CR_SO +}; + +static const uint32_t tcg_to_bc[10] = { + [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, + [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, + [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, + [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, + [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, + [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, + [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, +}; + +static void tcg_out_mov (TCGContext *s, int ret, int arg) +{ + tcg_out32 (s, OR | SAB (arg, ret, arg)); +} + +static void tcg_out_rld (TCGContext *s, int op, int ra, int rs, int sh, int mb) +{ + sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1); + mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f)); + tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb); +} + +static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg) +{ + if (arg == (int16_t) arg) + tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); + else { + tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); + if (arg & 0xffff) + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); + } +} + +static void tcg_out_movi (TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + int32_t arg32 = arg; + arg = type == TCG_TYPE_I32 ? arg & 0xffffffff : arg; + + if (arg == arg32) { + tcg_out_movi32 (s, ret, arg32); + } + else { + if ((uint64_t) arg >> 32) { + uint16_t h16 = arg >> 16; + uint16_t l16 = arg; + + tcg_out_movi32 (s, ret, arg >> 32); + tcg_out_rld (s, RLDICR, ret, ret, 32, 31); + if (h16) tcg_out32 (s, ORIS | RS (ret) | RA (ret) | h16); + if (l16) tcg_out32 (s, ORI | RS (ret) | RA (ret) | l16); + } + else { + tcg_out_movi32 (s, ret, arg32); + if (arg32 < 0) + tcg_out_rld (s, RLDICL, ret, ret, 0, 32); + } + } +} + +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 38) >> 38 == disp) + tcg_out32 (s, B | (disp & 0x3fffffc) | mask); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + +static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) +{ +#ifdef __APPLE__ + if (const_arg) { + tcg_out_b (s, LK, arg); + } + else { + tcg_out32 (s, MTSPR | RS (arg) | LR); + tcg_out32 (s, BCLR | BO_ALWAYS | LK); + } +#else + int reg; + + if (const_arg) { + reg = 2; + tcg_out_movi (s, TCG_TYPE_I64, reg, arg); + } + else reg = arg; + + tcg_out32 (s, LD | RT (0) | RA (reg)); + tcg_out32 (s, MTSPR | RA (0) | CTR); + tcg_out32 (s, LD | RT (11) | RA (reg) | 16); + tcg_out32 (s, LD | RT (2) | RA (reg) | 8); + tcg_out32 (s, BCCTR | BO_ALWAYS | LK); +#endif +} + +static void tcg_out_ldst (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) offset) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +static void tcg_out_ldsta (TCGContext *s, int ret, int addr, + int offset, int op1, int op2) +{ + if (offset == (int16_t) (offset & ~3)) + tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, offset); + tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); + } +} + +#if defined (CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; + +static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, + int addr_reg, int s_bits, int offset) +{ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); + + tcg_out32 (s, (RLWINM + | RA (r0) + | RS (addr_reg) + | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) + | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) + | ME (31 - CPU_TLB_ENTRY_BITS) + ) + ); + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); + tcg_out32 (s, (LWZU | RT (r1) | RA (r0) | offset)); + tcg_out32 (s, (RLWINM + | RA (r2) + | RS (addr_reg) + | SH (0) + | MB ((32 - s_bits) & 31) + | ME (31 - TARGET_PAGE_BITS) + ) + ); +#else + tcg_out_rld (s, RLDICL, r0, addr_reg, + 64 - TARGET_PAGE_BITS, + 64 - CPU_TLB_BITS); + tcg_out_rld (s, RLDICR, r0, r0, + CPU_TLB_ENTRY_BITS, + 63 - CPU_TLB_ENTRY_BITS); + + tcg_out32 (s, ADD | TAB (r0, r0, TCG_AREG0)); + tcg_out32 (s, LD_ADDR | RT (r1) | RA (r0) | offset); + + if (!s_bits) { + tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS); + } + else { + tcg_out_rld (s, RLDICL, r2, addr_reg, + 64 - TARGET_PAGE_BITS, + TARGET_PAGE_BITS - s_bits); + tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0); + } +#endif +} +#endif + +static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits, + offsetof (CPUState, tlb_table[mem_index][0].addr_read)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); + + switch (opc) { + case 0|4: + tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); + break; + case 1|4: + tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); + break; + case 2|4: + tcg_out32 (s, EXTSW | RA (data_reg) | RS (3)); + break; + case 0: + case 1: + case 2: + case 3: + if (data_reg != 3) + tcg_out_mov (s, data_reg, 3); + break; + } + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_read)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r0 = addr_reg; + r1 = 3; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + default: + case 0: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + break; + case 0|4: + tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); + break; + case 1: + if (bswap) + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0)); + break; + case 1|4: + if (bswap) { + tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + else + tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0)); + break; + case 2|4: + if (bswap) { + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, EXTSW | RA (data_reg) | RS (data_reg)); + } + else tcg_out32 (s, LWAX | TAB (data_reg, rbase, r0)); + break; + case 3: +#ifdef CONFIG_USE_GUEST_BASE + if (bswap) { + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0)); + tcg_out32 (s, LWBRX | TAB ( r1, rbase, r1)); + tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0); + } + else tcg_out32 (s, LDX | TAB (data_reg, rbase, r0)); +#else + if (bswap) { + tcg_out_movi32 (s, 0, 4); + tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); + tcg_out32 (s, LWBRX | RT ( r1) | RA (r0)); + tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0); + } + else tcg_out32 (s, LD | RT (data_reg) | RA (r0)); +#endif + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) +{ + int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap; +#ifdef CONFIG_SOFTMMU + int r2; + void *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + +#ifdef CONFIG_SOFTMMU + r0 = 3; + r1 = 4; + r2 = 0; + rbase = 0; + + tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc, + offsetof (CPUState, tlb_table[mem_index][0].addr_write)); + + tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L); + + label1_ptr = s->code_ptr; +#ifdef FAST_PATH + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); +#endif + + /* slow path */ + tcg_out_mov (s, 3, addr_reg); + tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc))); + tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index); + + tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); + + label2_ptr = s->code_ptr; + tcg_out32 (s, B); + + /* label1: fast path */ +#ifdef FAST_PATH + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); +#endif + + tcg_out32 (s, (LD_ADDEND + | RT (r0) + | RA (r0) + | (offsetof (CPUTLBEntry, addend) + - offsetof (CPUTLBEntry, addr_write)) + )); + /* r0 = env->tlb_table[mem_index][index].addend */ + tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); + /* r0 = env->tlb_table[mem_index][index].addend + addr */ + +#else /* !CONFIG_SOFTMMU */ +#if TARGET_LONG_BITS == 32 + tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32); +#endif + r1 = 3; + r0 = addr_reg; + rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch (opc) { + case 0: + tcg_out32 (s, STBX | SAB (data_reg, rbase, r0)); + break; + case 1: + if (bswap) + tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STHX | SAB (data_reg, rbase, r0)); + break; + case 2: + if (bswap) + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + else + tcg_out32 (s, STWX | SAB (data_reg, rbase, r0)); + break; + case 3: + if (bswap) { + tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0)); + tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); + tcg_out_rld (s, RLDICL, 0, data_reg, 32, 0); + tcg_out32 (s, STWBRX | SAB (0, rbase, r1)); + } + else tcg_out32 (s, STDX | SAB (data_reg, rbase, r0)); + break; + } + +#ifdef CONFIG_SOFTMMU + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); +#endif +} + +void tcg_target_qemu_prologue (TCGContext *s) +{ + int i, frame_size; +#ifndef __APPLE__ + uint64_t addr; +#endif + + frame_size = 0 + + 8 /* back chain */ + + 8 /* CR */ + + 8 /* LR */ + + 8 /* compiler doubleword */ + + 8 /* link editor doubleword */ + + 8 /* TOC save area */ + + TCG_STATIC_CALL_ARGS_SIZE + + ARRAY_SIZE (tcg_target_callee_save_regs) * 8 + ; + frame_size = (frame_size + 15) & ~15; + +#ifndef __APPLE__ + /* First emit adhoc function descriptor */ + addr = (uint64_t) s->code_ptr + 24; + tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */ + s->code_ptr += 16; /* skip TOC and environment pointer */ +#endif + + /* Prologue */ + tcg_out32 (s, MFSPR | RT (0) | LR); + tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff)); + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (STD + | RS (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16)); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_out_movi (s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE); +#endif + + tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + + /* Epilogue */ + tb_ret_addr = s->code_ptr; + + for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) + tcg_out32 (s, (LD + | RT (tcg_target_callee_save_regs[i]) + | RA (1) + | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE) + ) + ); + tcg_out32 (s, LD | RT (0) | RA (1) | (frame_size + 16)); + tcg_out32 (s, MTSPR | RS (0) | LR); + tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); + tcg_out32 (s, BCLR | BO_ALWAYS); +} + +static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); + else + tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX); +} + +static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); + else + tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX); +} + +static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + if (!si && rt == ra) + return; + + if (si == (int16_t) si) + tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); + else { + uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); + tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); + tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); + } +} + +static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si) +{ + /* XXX: suboptimal */ + if (si == (int16_t) si + || ((((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0)) + ppc_addi32 (s, rt, ra, si); + else { + tcg_out_movi (s, TCG_TYPE_I64, 0, si); + tcg_out32 (s, ADD | RT (rt) | RA (ra)); + } +} + +static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val) +{ + ppc_addi64 (s, reg, reg, val); +} + +static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, + int const_arg2, int cr, int arch64) +{ + int imm; + uint32_t op; + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + else if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + case TCG_COND_LT: + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GT: + if (const_arg2) { + if ((int16_t) arg2 == arg2) { + op = CMPI; + imm = 1; + break; + } + } + op = CMP; + imm = 0; + break; + + case TCG_COND_LTU: + case TCG_COND_GEU: + case TCG_COND_LEU: + case TCG_COND_GTU: + if (const_arg2) { + if ((uint16_t) arg2 == arg2) { + op = CMPLI; + imm = 1; + break; + } + } + op = CMPL; + imm = 0; + break; + + default: + tcg_abort (); + } + op |= BF (cr) | (arch64 << 21); + + if (imm) + tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); + else { + if (const_arg2) { + tcg_out_movi (s, TCG_TYPE_I64, 0, arg2); + tcg_out32 (s, op | RA (arg1) | RB (0)); + } + else + tcg_out32 (s, op | RA (arg1) | RB (arg2)); + } + +} + +static void tcg_out_bc (TCGContext *s, int bc, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) + tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); + else { + uint16_t val = *(uint16_t *) &s->code_ptr[2]; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, bc | (val & 0xfffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + } +} + +static void tcg_out_brcond (TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int arch64) +{ + tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, arch64); + tcg_out_bc (s, tcg_to_bc[cond], label_index); +} + +void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) +{ + TCGContext s; + unsigned long patch_size; + + s.code_ptr = (uint8_t *) jmp_addr; + tcg_out_b (&s, 0, addr); + patch_size = s.code_ptr - (uint8_t *) jmp_addr; + flush_icache_range (jmp_addr, jmp_addr + patch_size); +} + +static void tcg_out_op (TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 28; + } + else { + tcg_abort (); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + { + TCGLabel *l = &s->labels[args[0]]; + + if (l->has_value) { + tcg_out_b (s, 0, l->u.value); + } + else { + uint32_t val = *(uint32_t *) s->code_ptr; + + /* Thanks to Andrzej Zaborowski */ + tcg_out32 (s, B | (val & 0x3fffffc)); + tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + } + } + break; + case INDEX_op_call: + tcg_out_call (s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_b (s, 0, args[0]); + } + else { + tcg_out32 (s, MTSPR | RS (args[0]) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + break; + case INDEX_op_movi_i32: + tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + break; + case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); + tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); + break; + case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX); + break; + case INDEX_op_ld_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX); + break; + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); + break; + case INDEX_op_st_i64: + tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX); + break; + + case INDEX_op_add_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i32: + if (const_args[2]) + ppc_addi32 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_and_i64: + case INDEX_op_and_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, AND | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_or_i64: + case INDEX_op_or_i32: + if (const_args[2]) { + if (args[2] & 0xffff) { + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + if (args[2] >> 16) + tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + else { + tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + } + } + else + tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_xor_i64: + case INDEX_op_xor_i32: + if (const_args[2]) { + if ((args[2] & 0xffff) == args[2]) + tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); + else if ((args[2] & 0xffff0000) == args[2]) + tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) + | ((args[2] >> 16) & 0xffff)); + else { + tcg_out_movi (s, (opc == INDEX_op_and_i32 + ? TCG_TYPE_I32 + : TCG_TYPE_I64), + 0, args[2]); + tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); + } + } + else + tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + if (args[2] == (int16_t) args[2]) + tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) + | (args[2] & 0xffff)); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); + tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); + } + } + else + tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_div_i32: + tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_divu_i32: + tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); + break; + + case INDEX_op_rem_i32: + tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_remu_i32: + tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLW | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_shl_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (args[2]) + | MB (0) + | ME (31 - args[2]) + ) + ); + } + else + tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i32: + if (const_args[2]) { + tcg_out32 (s, (RLWINM + | RA (args[0]) + | RS (args[1]) + | SH (32 - args[2]) + | MB (args[2]) + | ME (31) + ) + ); + } + else + tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i32: + if (const_args[2]) + tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); + else + tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 0); + break; + + case INDEX_op_brcond_i64: + tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 1); + break; + + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); + break; + + case INDEX_op_add_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], args[2]); + else + tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_sub_i64: + if (const_args[2]) + ppc_addi64 (s, args[0], args[1], -args[2]); + else + tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); + break; + + case INDEX_op_shl_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICR, args[0], args[1], args[2], 63 - args[2]); + else + tcg_out32 (s, SLD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_shr_i64: + if (const_args[2]) + tcg_out_rld (s, RLDICL, args[0], args[1], 64 - args[2], args[2]); + else + tcg_out32 (s, SRD | SAB (args[1], args[0], args[2])); + break; + case INDEX_op_sar_i64: + if (const_args[2]) { + int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1); + tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh); + } + else + tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2])); + break; + + case INDEX_op_mul_i64: + tcg_out32 (s, MULLD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_div_i64: + tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_divu_i64: + tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2])); + break; + case INDEX_op_rem_i64: + tcg_out32 (s, DIVD | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + case INDEX_op_remu_i64: + tcg_out32 (s, DIVDU | TAB (0, args[1], args[2])); + tcg_out32 (s, MULLD | TAB (0, 0, args[2])); + tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld (s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld (s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld (s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld (s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld (s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld (s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld (s, args, 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st (s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st (s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st (s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st (s, args, 3); + break; + + case INDEX_op_ext8s_i32: + case INDEX_op_ext8s_i64: + c = EXTSB; + goto gen_ext; + case INDEX_op_ext16s_i32: + case INDEX_op_ext16s_i64: + c = EXTSH; + goto gen_ext; + case INDEX_op_ext32s_i64: + c = EXTSW; + goto gen_ext; + gen_ext: + tcg_out32 (s, c | RS (args[1]) | RA (args[0])); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_movi_i64, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + { INDEX_op_div_i32, { "r", "r", "r" } }, + { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_rem_i32, { "r", "r", "r" } }, + { INDEX_op_remu_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "ri" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + { INDEX_op_brcond_i64, { "r", "ri" } }, + + { INDEX_op_neg_i32, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "r", "ri" } }, + { INDEX_op_sub_i64, { "r", "r", "ri" } }, + { INDEX_op_and_i64, { "r", "r", "rZ" } }, + { INDEX_op_or_i64, { "r", "r", "rZ" } }, + { INDEX_op_xor_i64, { "r", "r", "rZ" } }, + + { INDEX_op_shl_i64, { "r", "r", "ri" } }, + { INDEX_op_shr_i64, { "r", "r", "ri" } }, + { INDEX_op_sar_i64, { "r", "r", "ri" } }, + + { INDEX_op_mul_i64, { "r", "r", "r" } }, + { INDEX_op_div_i64, { "r", "r", "r" } }, + { INDEX_op_divu_i64, { "r", "r", "r" } }, + { INDEX_op_rem_i64, { "r", "r", "r" } }, + { INDEX_op_remu_i64, { "r", "r", "r" } }, + + { INDEX_op_neg_i64, { "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "S", "S" } }, + { INDEX_op_qemu_st16, { "S", "S" } }, + { INDEX_op_qemu_st32, { "S", "S" } }, + { INDEX_op_qemu_st64, { "S", "S" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8s_i64, { "r", "r" } }, + { INDEX_op_ext16s_i64, { "r", "r" } }, + { INDEX_op_ext32s_i64, { "r", "r" } }, + + { -1 }, +}; + +void tcg_target_init (TCGContext *s) +{ + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); + tcg_regset_set32 (tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_R0) | +#ifdef __APPLE__ + (1 << TCG_REG_R2) | +#endif + (1 << TCG_REG_R3) | + (1 << TCG_REG_R4) | + (1 << TCG_REG_R5) | + (1 << TCG_REG_R6) | + (1 << TCG_REG_R7) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11) | + (1 << TCG_REG_R12) + ); + + tcg_regset_clear (s->reserved_regs); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0); + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1); +#ifndef __APPLE__ + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2); +#endif + tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13); + +#ifdef CONFIG_USE_GUEST_BASE + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); +#endif + + tcg_add_target_add_op_defs (ppc_op_defs); +} diff --git a/qemu/qemu-git/tcg/ppc64/tcg-target.h b/qemu/qemu-git/tcg/ppc64/tcg-target.h new file mode 100644 index 0000000..94b800f --- /dev/null +++ b/qemu/qemu-git/tcg/ppc64/tcg-target.h @@ -0,0 +1,85 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_PPC64 1 + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R16, + TCG_REG_R17, + TCG_REG_R18, + TCG_REG_R19, + TCG_REG_R20, + TCG_REG_R21, + TCG_REG_R22, + TCG_REG_R23, + TCG_REG_R24, + TCG_REG_R25, + TCG_REG_R26, + TCG_REG_R27, + TCG_REG_R28, + TCG_REG_R29, + TCG_REG_R30, + TCG_REG_R31 +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R1 +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 48 + +/* optional instructions */ +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_div_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 + +#define TCG_AREG0 TCG_REG_R27 +#define TCG_AREG1 TCG_REG_R24 +#define TCG_AREG2 TCG_REG_R25 + +#define TCG_TARGET_HAS_GUEST_BASE diff --git a/qemu/qemu-git/tcg/s390/.svn/all-wcprops b/qemu/qemu-git/tcg/s390/.svn/all-wcprops new file mode 100644 index 0000000..27f6b30 --- /dev/null +++ b/qemu/qemu-git/tcg/s390/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 48 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/s390 +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/s390/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 61 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/s390/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/s390/.svn/entries b/qemu/qemu-git/tcg/s390/.svn/entries new file mode 100644 index 0000000..da0d838 --- /dev/null +++ b/qemu/qemu-git/tcg/s390/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/s390 +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +196d09851dc196bf4e4f77be61076d51 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2922 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +a04f358b2b8f2c157a608cdc450336e6 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2100 + diff --git a/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..356b1a4 --- /dev/null +++ b/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,105 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2009 Ulrich Hecht + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static const int tcg_target_reg_alloc_order[] = { +}; + +static const int tcg_target_call_iarg_regs[] = { +}; + +static const int tcg_target_call_oarg_regs[] = { +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + tcg_abort(); +} + +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + tcg_abort(); + return 0; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + tcg_abort(); + return 0; +} + +/* Test if a constant matches the constraint. */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + tcg_abort(); + return 0; +} + +/* load a register with an immediate value */ +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_abort(); +} + +/* load data without address translation or endianness conversion */ +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_abort(); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_abort(); +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + tcg_abort(); +} + +void tcg_target_init(TCGContext *s) +{ + /* gets called with KVM */ +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + /* gets called with KVM */ +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_abort(); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_abort(); +} diff --git a/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..91b931d --- /dev/null +++ b/qemu/qemu-git/tcg/s390/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,69 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2009 Ulrich Hecht + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_S390 1 + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15 +}; +#define TCG_TARGET_NB_REGS 16 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R15 +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +enum { + /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R10, + TCG_AREG1 = TCG_REG_R7, + TCG_AREG2 = TCG_REG_R8, + TCG_AREG3 = TCG_REG_R9, +}; + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +#if QEMU_GNUC_PREREQ(4, 1) + __builtin___clear_cache((char *) start, (char *) stop); +#else +#error not implemented +#endif +} diff --git a/qemu/qemu-git/tcg/s390/tcg-target.c b/qemu/qemu-git/tcg/s390/tcg-target.c new file mode 100644 index 0000000..356b1a4 --- /dev/null +++ b/qemu/qemu-git/tcg/s390/tcg-target.c @@ -0,0 +1,105 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2009 Ulrich Hecht + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static const int tcg_target_reg_alloc_order[] = { +}; + +static const int tcg_target_call_iarg_regs[] = { +}; + +static const int tcg_target_call_oarg_regs[] = { +}; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + tcg_abort(); +} + +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + tcg_abort(); + return 0; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + tcg_abort(); + return 0; +} + +/* Test if a constant matches the constraint. */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + tcg_abort(); + return 0; +} + +/* load a register with an immediate value */ +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_abort(); +} + +/* load data without address translation or endianness conversion */ +static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_abort(); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + tcg_abort(); +} + +static inline void tcg_out_op(TCGContext *s, int opc, + const TCGArg *args, const int *const_args) +{ + tcg_abort(); +} + +void tcg_target_init(TCGContext *s) +{ + /* gets called with KVM */ +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + /* gets called with KVM */ +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_abort(); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_abort(); +} diff --git a/qemu/qemu-git/tcg/s390/tcg-target.h b/qemu/qemu-git/tcg/s390/tcg-target.h new file mode 100644 index 0000000..91b931d --- /dev/null +++ b/qemu/qemu-git/tcg/s390/tcg-target.h @@ -0,0 +1,69 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2009 Ulrich Hecht + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_S390 1 + +#define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_WORDS_BIGENDIAN + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15 +}; +#define TCG_TARGET_NB_REGS 16 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R15 +#define TCG_TARGET_STACK_ALIGN 8 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +enum { + /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R10, + TCG_AREG1 = TCG_REG_R7, + TCG_AREG2 = TCG_REG_R8, + TCG_AREG3 = TCG_REG_R9, +}; + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +#if QEMU_GNUC_PREREQ(4, 1) + __builtin___clear_cache((char *) start, (char *) stop); +#else +#error not implemented +#endif +} diff --git a/qemu/qemu-git/tcg/sparc/.svn/all-wcprops b/qemu/qemu-git/tcg/sparc/.svn/all-wcprops new file mode 100644 index 0000000..6137292 --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 49 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/sparc +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/sparc/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 62 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/sparc/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/sparc/.svn/entries b/qemu/qemu-git/tcg/sparc/.svn/entries new file mode 100644 index 0000000..85306ba --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/sparc +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +cc77a7d54b957ded0a3786999f2e9927 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +44214 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +a9dea207a3126127d800fcb06a8ac4db +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +3583 + diff --git a/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..dd7a598 --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1402 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%g0", + "%g1", + "%g2", + "%g3", + "%g4", + "%g5", + "%g6", + "%g7", + "%o0", + "%o1", + "%o2", + "%o3", + "%o4", + "%o5", + "%o6", + "%o7", + "%l0", + "%l1", + "%l2", + "%l3", + "%l4", + "%l5", + "%l6", + "%l7", + "%i0", + "%i1", + "%i2", + "%i3", + "%i4", + "%i5", + "%i6", + "%i7", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_O0, + TCG_REG_O1, +}; + +static inline int check_fit_tl(tcg_target_long val, unsigned int bits) +{ + return (val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val; +} + +static inline int check_fit_i32(uint32_t val, unsigned int bits) +{ + return ((val << (32 - bits)) >> (32 - bits)) == val; +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_SPARC_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_SPARC_WDISP22: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 22)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; + break; + case R_SPARC_WDISP19: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 19)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + // Helper args + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S13; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) + return 1; + else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) + return 1; + else + return 0; +} + +#define INSN_OP(x) ((x) << 30) +#define INSN_OP2(x) ((x) << 22) +#define INSN_OP3(x) ((x) << 19) +#define INSN_OPF(x) ((x) << 5) +#define INSN_RD(x) ((x) << 25) +#define INSN_RS1(x) ((x) << 14) +#define INSN_RS2(x) (x) +#define INSN_ASI(x) ((x) << 5) + +#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) +#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff) +#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) + +#define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) +#define COND_N 0x0 +#define COND_E 0x1 +#define COND_LE 0x2 +#define COND_L 0x3 +#define COND_LEU 0x4 +#define COND_CS 0x5 +#define COND_NEG 0x6 +#define COND_VS 0x7 +#define COND_A 0x8 +#define COND_NE 0x9 +#define COND_G 0xa +#define COND_GE 0xb +#define COND_GU 0xc +#define COND_CC 0xd +#define COND_POS 0xe +#define COND_VC 0xf +#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2)) + +#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00)) +#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10)) +#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01)) +#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02)) +#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12)) +#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03)) +#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) +#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) +#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10)) +#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c)) +#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) +#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) +#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f)) +#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09)) +#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) +#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) + +#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) +#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) +#define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27)) + +#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12)) +#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12)) +#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12)) + +#define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0)) +#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0)) +#define JMPL (INSN_OP(2) | INSN_OP3(0x38)) +#define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) +#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d)) +#define SETHI (INSN_OP(0) | INSN_OP2(0x4)) +#define CALL INSN_OP(1) +#define LDUB (INSN_OP(3) | INSN_OP3(0x01)) +#define LDSB (INSN_OP(3) | INSN_OP3(0x09)) +#define LDUH (INSN_OP(3) | INSN_OP3(0x02)) +#define LDSH (INSN_OP(3) | INSN_OP3(0x0a)) +#define LDUW (INSN_OP(3) | INSN_OP3(0x00)) +#define LDSW (INSN_OP(3) | INSN_OP3(0x08)) +#define LDX (INSN_OP(3) | INSN_OP3(0x0b)) +#define STB (INSN_OP(3) | INSN_OP3(0x05)) +#define STH (INSN_OP(3) | INSN_OP3(0x06)) +#define STW (INSN_OP(3) | INSN_OP3(0x04)) +#define STX (INSN_OP(3) | INSN_OP3(0x0e)) +#define LDUBA (INSN_OP(3) | INSN_OP3(0x11)) +#define LDSBA (INSN_OP(3) | INSN_OP3(0x19)) +#define LDUHA (INSN_OP(3) | INSN_OP3(0x12)) +#define LDSHA (INSN_OP(3) | INSN_OP3(0x1a)) +#define LDUWA (INSN_OP(3) | INSN_OP3(0x10)) +#define LDSWA (INSN_OP(3) | INSN_OP3(0x18)) +#define LDXA (INSN_OP(3) | INSN_OP3(0x1b)) +#define STBA (INSN_OP(3) | INSN_OP3(0x15)) +#define STHA (INSN_OP(3) | INSN_OP3(0x16)) +#define STWA (INSN_OP(3) | INSN_OP3(0x14)) +#define STXA (INSN_OP(3) | INSN_OP3(0x1e)) + +#ifndef ASI_PRIMARY_LITTLE +#define ASI_PRIMARY_LITTLE 0x88 +#endif + +static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, + int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_RS2(rs2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1, + uint32_t offset, int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_IMM13(offset)); +} + +static void tcg_out_arithc(TCGContext *s, int rd, int rs1, + int val2, int val2const, int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) + | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2))); +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR); +} + +static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10)); +} + +static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR); +} + +static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg) +{ + if (check_fit_tl(arg, 13)) + tcg_out_movi_imm13(s, ret, arg); + else { + tcg_out_sethi(s, ret, arg); + if (arg & 0x3ff) + tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR); + } +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + /* All 32-bit constants, as well as 64-bit constants with + no high bits set go through movi_imm32. */ + if (TCG_TARGET_REG_BITS == 32 + || type == TCG_TYPE_I32 + || (arg & ~(tcg_target_long)0xffffffff) == 0) { + tcg_out_movi_imm32(s, ret, arg); + } else if (check_fit_tl(arg, 13)) { + /* A 13-bit constant sign-extended to 64-bits. */ + tcg_out_movi_imm13(s, ret, arg); + } else if (check_fit_tl(arg, 32)) { + /* A 32-bit constant sign-extended to 64-bits. */ + tcg_out_sethi(s, ret, ~arg); + tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR); + } else { + tcg_out_movi_imm32(s, TCG_REG_I4, arg >> (TCG_TARGET_REG_BITS / 2)); + tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX); + tcg_out_movi_imm32(s, ret, arg); + tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR); + } +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_sethi(s, ret, arg); + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + if (!check_fit_tl(arg, 10)) + tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL); + if (TCG_TARGET_REG_BITS == 64) { + tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); + } else { + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); + } +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op) +{ + if (check_fit_tl(offset, 13)) + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | + INSN_IMM13(offset)); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(addr)); + } +} + +static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr, + int offset, int op, int asi) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_ASI(asi) | INSN_RS2(addr)); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, ret, arg1, arg2, LDUW); + else + tcg_out_ldst(s, ret, arg1, arg2, LDX); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, arg, arg1, arg2, STW); + else + tcg_out_ldst(s, arg, arg1, arg2, STX); +} + +static inline void tcg_out_sety(TCGContext *s, int rs) +{ + tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); +} + +static inline void tcg_out_rdy(TCGContext *s, int rd) +{ + tcg_out32(s, RDY | INSN_RD(rd)); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); + } + } +} + +static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_AND); + else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND); + } + } +} + +static void tcg_out_div32(TCGContext *s, int rd, int rs1, + int val2, int val2const, int uns) +{ + /* Load Y with the sign/zero extension of RS1 to 64-bits. */ + if (uns) { + tcg_out_sety(s, TCG_REG_G0); + } else { + tcg_out_arithi(s, TCG_REG_I5, rs1, 31, SHIFT_SRA); + tcg_out_sety(s, TCG_REG_I5); + } + + tcg_out_arithc(s, rd, rs1, val2, val2const, + uns ? ARITH_UDIV : ARITH_SDIV); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out_sethi(s, TCG_REG_G0, 0); +} + +static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) + | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); + } +} + +#if TCG_TARGET_REG_BITS == 64 +static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | + INSN_OFF19(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | 0)); + } +} +#endif + +static const uint8_t tcg_cond_to_bcond[10] = { + [TCG_COND_EQ] = COND_E, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_L, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_G, + [TCG_COND_LTU] = COND_CS, + [TCG_COND_GEU] = COND_CC, + [TCG_COND_LEU] = COND_LEU, + [TCG_COND_GTU] = COND_GU, +}; + +static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const) +{ + tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC); +} + +static void tcg_out_brcond_i32(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp(s, arg1, arg2, const_arg2); + tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} + +#if TCG_TARGET_REG_BITS == 64 +static void tcg_out_brcond_i64(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp(s, arg1, arg2, const_arg2); + tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} +#else +static void tcg_out_brcond2_i32(TCGContext *s, int cond, + TCGArg al, TCGArg ah, + TCGArg bl, int blconst, + TCGArg bh, int bhconst, int label_dest) +{ + int cc, label_next = gen_new_label(); + + tcg_out_cmp(s, ah, bh, bhconst); + + /* Note that we fill one of the delay slots with the second compare. */ + switch (cond) { + case TCG_COND_EQ: + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_next); + tcg_out_cmp(s, al, bl, blconst); + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_EQ], 0); + tcg_out_branch_i32(s, cc, label_dest); + break; + + case TCG_COND_NE: + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_dest); + tcg_out_cmp(s, al, bl, blconst); + tcg_out_branch_i32(s, cc, label_dest); + break; + + default: + /* ??? One could fairly easily special-case 64-bit unsigned + compares against 32-bit zero-extended constants. For instance, + we know that (unsigned)AH < 0 is false and need not emit it. + Similarly, (unsigned)AH > 0 being true implies AH != 0, so the + second branch will never be taken. */ + cc = INSN_COND(tcg_cond_to_bcond[cond], 0); + tcg_out_branch_i32(s, cc, label_dest); + tcg_out_nop(s); + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_next); + tcg_out_cmp(s, al, bl, blconst); + cc = INSN_COND(tcg_cond_to_bcond[tcg_unsigned_cond(cond)], 0); + tcg_out_branch_i32(s, cc, label_dest); + break; + } + tcg_out_nop(s); + + tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); +} +#endif + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | + INSN_IMM13(-TCG_TARGET_STACK_MINFRAME)); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) | + INSN_RS2(TCG_REG_G0)); + tcg_out_nop(s); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static const void * const qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static const void * const qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#if TARGET_LONG_BITS == 32 +#define TARGET_LD_OP LDUW +#else +#define TARGET_LD_OP LDX +#endif + +#if TARGET_PHYS_ADDR_BITS == 32 +#define TARGET_ADDEND_LD_OP LDUW +#else +#define TARGET_ADDEND_LD_OP LDX +#endif + +#ifdef __arch64__ +#define HOST_LD_OP LDX +#define HOST_ST_OP STX +#define HOST_SLL_OP SHIFT_SLLX +#define HOST_SRA_OP SHIFT_SRAX +#else +#define HOST_LD_OP LDUW +#define HOST_ST_OP STW +#define HOST_SLL_OP SHIFT_SLL +#define HOST_SRA_OP SHIFT_SRA +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_read)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 + or + be,pt %xcc label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_ld_helper[s_bits](arg0, arg1) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + + /* data_reg = sign_extend(arg0) */ + switch(opc) { + case 0 | 4: + /* sll arg0, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8, + HOST_SLL_OP); + /* sra data_reg, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP); + break; + case 1 | 4: + /* sll arg0, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, arg0, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP); + /* sra data_reg, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP); + break; + case 2 | 4: + /* sll arg0, 32, data_reg */ + tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP); + /* sra data_reg, 32, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP); + break; + case 0: + case 1: + case 2: + case 3: + default: + /* mov */ + tcg_out_mov(s, data_reg, arg0); + break; + } + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot */ + tcg_out_nop(s); + + /* label1: */ +#if TARGET_LONG_BITS == 32 + /* be label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* ldub [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUB); + break; + case 0 | 4: + /* ldsb [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUH); +#else + /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 1 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSH); +#else + /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUW); +#else + /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSW); +#else + /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldx [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDX); +#else + /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_write)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 + or + be,pt %xcc label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_mov(s, arg1, data_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot) */ + tcg_out_nop(s); + +#if TARGET_LONG_BITS == 32 + /* be label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* stb data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* sth data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STH); +#else + /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* stw data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STW); +#else + /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* stx data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STX); +#else + /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) | + INSN_IMM13(8)); + tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) | + INSN_RS2(TCG_REG_G0)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_IMM13((args[0] & 0x1fff))); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out32(s, CALL | ((((tcg_target_ulong)args[0] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + else { + tcg_out_ld_ptr(s, TCG_REG_I5, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + break; + case INDEX_op_jmp: + case INDEX_op_br: + tcg_out_branch_i32(s, COND_A, args[0]); + tcg_out_nop(s); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + +#if TCG_TARGET_REG_BITS == 64 +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32): \ + glue(glue(case INDEX_op_, x), _i64) +#else +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32) +#endif + OP_32_64(ld8u): + tcg_out_ldst(s, args[0], args[1], args[2], LDUB); + break; + OP_32_64(ld8s): + tcg_out_ldst(s, args[0], args[1], args[2], LDSB); + break; + OP_32_64(ld16u): + tcg_out_ldst(s, args[0], args[1], args[2], LDUH); + break; + OP_32_64(ld16s): + tcg_out_ldst(s, args[0], args[1], args[2], LDSH); + break; + case INDEX_op_ld_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_ld32u_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], LDUW); + break; + OP_32_64(st8): + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + OP_32_64(st16): + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_st32_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + OP_32_64(add): + c = ARITH_ADD; + goto gen_arith; + OP_32_64(sub): + c = ARITH_SUB; + goto gen_arith; + OP_32_64(and): + c = ARITH_AND; + goto gen_arith; + OP_32_64(or): + c = ARITH_OR; + goto gen_arith; + OP_32_64(xor): + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_shl_i32: + c = SHIFT_SLL; + goto gen_arith; + case INDEX_op_shr_i32: + c = SHIFT_SRL; + goto gen_arith; + case INDEX_op_sar_i32: + c = SHIFT_SRA; + goto gen_arith; + case INDEX_op_mul_i32: + c = ARITH_UMUL; + goto gen_arith; + + case INDEX_op_div_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0); + break; + case INDEX_op_divu_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1); + break; + + case INDEX_op_rem_i32: + case INDEX_op_remu_i32: + tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_remu_i32); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_UMUL); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; +#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_brcond2_i32: + tcg_out_brcond2_i32(s, args[4], args[0], args[1], + args[2], const_args[2], + args[3], const_args[3], args[5]); + break; + case INDEX_op_add2_i32: + tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], + ARITH_ADDCC); + tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], + ARITH_ADDX); + break; + case INDEX_op_sub2_i32: + tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], + ARITH_SUBCC); + tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], + ARITH_SUBX); + break; + case INDEX_op_mulu2_i32: + tcg_out_arithc(s, args[0], args[2], args[3], const_args[3], + ARITH_UMUL); + tcg_out_rdy(s, args[1]); + break; +#endif + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDSW); + break; + case INDEX_op_ld_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDX); + break; + case INDEX_op_st_i64: + tcg_out_ldst(s, args[0], args[1], args[2], STX); + break; + case INDEX_op_shl_i64: + c = SHIFT_SLLX; + goto gen_arith; + case INDEX_op_shr_i64: + c = SHIFT_SRLX; + goto gen_arith; + case INDEX_op_sar_i64: + c = SHIFT_SRAX; + goto gen_arith; + case INDEX_op_mul_i64: + c = ARITH_MULX; + goto gen_arith; + case INDEX_op_div_i64: + c = ARITH_SDIVX; + goto gen_arith; + case INDEX_op_divu_i64: + c = ARITH_UDIVX; + goto gen_arith; + case INDEX_op_rem_i64: + case INDEX_op_remu_i64: + tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_MULX); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; + case INDEX_op_ext32s_i64: + if (const_args[1]) { + tcg_out_movi(s, TCG_TYPE_I64, args[0], (int32_t)args[1]); + } else { + tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA); + } + break; + case INDEX_op_ext32u_i64: + if (const_args[1]) { + tcg_out_movi_imm32(s, args[0], args[1]); + } else { + tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL); + } + break; + + case INDEX_op_brcond_i64: + tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + +#endif + gen_arith: + tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c); + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } +} + +static const TCGTargetOpDef sparc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "rJ" } }, + { INDEX_op_mul_i32, { "r", "r", "rJ" } }, + { INDEX_op_div_i32, { "r", "r", "rJ" } }, + { INDEX_op_divu_i32, { "r", "r", "rJ" } }, + { INDEX_op_rem_i32, { "r", "r", "rJ" } }, + { INDEX_op_remu_i32, { "r", "r", "rJ" } }, + { INDEX_op_sub_i32, { "r", "r", "rJ" } }, + { INDEX_op_and_i32, { "r", "r", "rJ" } }, + { INDEX_op_or_i32, { "r", "r", "rJ" } }, + { INDEX_op_xor_i32, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i32, { "r", "r", "rJ" } }, + { INDEX_op_shr_i32, { "r", "r", "rJ" } }, + { INDEX_op_sar_i32, { "r", "r", "rJ" } }, + + { INDEX_op_brcond_i32, { "r", "rJ" } }, +#if TCG_TARGET_REG_BITS == 32 + { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } }, + { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } }, +#endif + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + +#if TCG_TARGET_REG_BITS == 64 + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_qemu_ld64, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L" } }, + + { INDEX_op_add_i64, { "r", "r", "rJ" } }, + { INDEX_op_mul_i64, { "r", "r", "rJ" } }, + { INDEX_op_div_i64, { "r", "r", "rJ" } }, + { INDEX_op_divu_i64, { "r", "r", "rJ" } }, + { INDEX_op_rem_i64, { "r", "r", "rJ" } }, + { INDEX_op_remu_i64, { "r", "r", "rJ" } }, + { INDEX_op_sub_i64, { "r", "r", "rJ" } }, + { INDEX_op_and_i64, { "r", "r", "rJ" } }, + { INDEX_op_or_i64, { "r", "r", "rJ" } }, + { INDEX_op_xor_i64, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i64, { "r", "r", "rJ" } }, + { INDEX_op_shr_i64, { "r", "r", "rJ" } }, + { INDEX_op_sar_i64, { "r", "r", "rJ" } }, + { INDEX_op_ext32s_i64, { "r", "ri" } }, + { INDEX_op_ext32u_i64, { "r", "ri" } }, + + { INDEX_op_brcond_i64, { "r", "rJ" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); +#if TCG_TARGET_REG_BITS == 64 + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); +#endif + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_G1) | + (1 << TCG_REG_G2) | + (1 << TCG_REG_G3) | + (1 << TCG_REG_G4) | + (1 << TCG_REG_G5) | + (1 << TCG_REG_G6) | + (1 << TCG_REG_G7) | + (1 << TCG_REG_O0) | + (1 << TCG_REG_O1) | + (1 << TCG_REG_O2) | + (1 << TCG_REG_O3) | + (1 << TCG_REG_O4) | + (1 << TCG_REG_O5) | + (1 << TCG_REG_O7)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); +#if TCG_TARGET_REG_BITS == 64 + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7); + tcg_add_target_add_op_defs(sparc_op_defs); +} diff --git a/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..d27ed5a --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,129 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_SPARC 1 + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +#define TCG_TARGET_REG_BITS 64 +#else +#define TCG_TARGET_REG_BITS 32 +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_G0 = 0, + TCG_REG_G1, + TCG_REG_G2, + TCG_REG_G3, + TCG_REG_G4, + TCG_REG_G5, + TCG_REG_G6, + TCG_REG_G7, + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, + TCG_REG_O6, + TCG_REG_O7, + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, + TCG_REG_I5, + TCG_REG_I6, + TCG_REG_I7, +}; + +#define TCG_CT_CONST_S11 0x100 +#define TCG_CT_CONST_S13 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_I6 +#ifdef __arch64__ +// Reserve space for AREG0 +#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16) +#define TCG_TARGET_STACK_ALIGN 16 +#else +// AREG0 + one word for alignment +#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME +#define TCG_TARGET_STACK_ALIGN 8 +#endif + +/* optional instructions */ +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_div_i64 + +#if TCG_TARGET_REG_BITS == 64 +#define TCG_TARGET_HAS_ext32s_i64 +#define TCG_TARGET_HAS_ext32u_i64 +#endif + +//#define TCG_TARGET_HAS_bswap32_i32 +//#define TCG_TARGET_HAS_bswap64_i64 +//#define TCG_TARGET_HAS_neg_i32 +//#define TCG_TARGET_HAS_neg_i64 + + +/* Note: must be synced with dyngen-exec.h and Makefile.target */ +#ifdef CONFIG_SOLARIS +#define TCG_AREG0 TCG_REG_G2 +#define TCG_AREG1 TCG_REG_G3 +#define TCG_AREG2 TCG_REG_G4 +#elif defined(__sparc_v9__) +#define TCG_AREG0 TCG_REG_G5 +#define TCG_AREG1 TCG_REG_G6 +#define TCG_AREG2 TCG_REG_G7 +#else +#define TCG_AREG0 TCG_REG_G6 +#define TCG_AREG1 TCG_REG_G1 +#define TCG_AREG2 TCG_REG_G2 +#endif + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(8UL - 1UL); + stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); + + for (; p < stop; p += 8) + __asm__ __volatile__("flush\t%0" : : "r" (p)); +} diff --git a/qemu/qemu-git/tcg/sparc/tcg-target.c b/qemu/qemu-git/tcg/sparc/tcg-target.c new file mode 100644 index 0000000..dd7a598 --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/tcg-target.c @@ -0,0 +1,1402 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%g0", + "%g1", + "%g2", + "%g3", + "%g4", + "%g5", + "%g6", + "%g7", + "%o0", + "%o1", + "%o2", + "%o3", + "%o4", + "%o5", + "%o6", + "%o7", + "%l0", + "%l1", + "%l2", + "%l3", + "%l4", + "%l5", + "%l6", + "%l7", + "%i0", + "%i1", + "%i2", + "%i3", + "%i4", + "%i5", + "%i6", + "%i7", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_O0, + TCG_REG_O1, +}; + +static inline int check_fit_tl(tcg_target_long val, unsigned int bits) +{ + return (val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val; +} + +static inline int check_fit_i32(uint32_t val, unsigned int bits) +{ + return ((val << (32 - bits)) >> (32 - bits)) == val; +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch (type) { + case R_SPARC_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_SPARC_WDISP22: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 22)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; + break; + case R_SPARC_WDISP19: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 19)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + // Helper args + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S13; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) + return 1; + else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) + return 1; + else + return 0; +} + +#define INSN_OP(x) ((x) << 30) +#define INSN_OP2(x) ((x) << 22) +#define INSN_OP3(x) ((x) << 19) +#define INSN_OPF(x) ((x) << 5) +#define INSN_RD(x) ((x) << 25) +#define INSN_RS1(x) ((x) << 14) +#define INSN_RS2(x) (x) +#define INSN_ASI(x) ((x) << 5) + +#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) +#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff) +#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) + +#define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) +#define COND_N 0x0 +#define COND_E 0x1 +#define COND_LE 0x2 +#define COND_L 0x3 +#define COND_LEU 0x4 +#define COND_CS 0x5 +#define COND_NEG 0x6 +#define COND_VS 0x7 +#define COND_A 0x8 +#define COND_NE 0x9 +#define COND_G 0xa +#define COND_GE 0xb +#define COND_GU 0xc +#define COND_CC 0xd +#define COND_POS 0xe +#define COND_VC 0xf +#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2)) + +#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00)) +#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10)) +#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01)) +#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02)) +#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12)) +#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03)) +#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) +#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) +#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10)) +#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c)) +#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) +#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) +#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f)) +#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09)) +#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) +#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) + +#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) +#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) +#define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27)) + +#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12)) +#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12)) +#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12)) + +#define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0)) +#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0)) +#define JMPL (INSN_OP(2) | INSN_OP3(0x38)) +#define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) +#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d)) +#define SETHI (INSN_OP(0) | INSN_OP2(0x4)) +#define CALL INSN_OP(1) +#define LDUB (INSN_OP(3) | INSN_OP3(0x01)) +#define LDSB (INSN_OP(3) | INSN_OP3(0x09)) +#define LDUH (INSN_OP(3) | INSN_OP3(0x02)) +#define LDSH (INSN_OP(3) | INSN_OP3(0x0a)) +#define LDUW (INSN_OP(3) | INSN_OP3(0x00)) +#define LDSW (INSN_OP(3) | INSN_OP3(0x08)) +#define LDX (INSN_OP(3) | INSN_OP3(0x0b)) +#define STB (INSN_OP(3) | INSN_OP3(0x05)) +#define STH (INSN_OP(3) | INSN_OP3(0x06)) +#define STW (INSN_OP(3) | INSN_OP3(0x04)) +#define STX (INSN_OP(3) | INSN_OP3(0x0e)) +#define LDUBA (INSN_OP(3) | INSN_OP3(0x11)) +#define LDSBA (INSN_OP(3) | INSN_OP3(0x19)) +#define LDUHA (INSN_OP(3) | INSN_OP3(0x12)) +#define LDSHA (INSN_OP(3) | INSN_OP3(0x1a)) +#define LDUWA (INSN_OP(3) | INSN_OP3(0x10)) +#define LDSWA (INSN_OP(3) | INSN_OP3(0x18)) +#define LDXA (INSN_OP(3) | INSN_OP3(0x1b)) +#define STBA (INSN_OP(3) | INSN_OP3(0x15)) +#define STHA (INSN_OP(3) | INSN_OP3(0x16)) +#define STWA (INSN_OP(3) | INSN_OP3(0x14)) +#define STXA (INSN_OP(3) | INSN_OP3(0x1e)) + +#ifndef ASI_PRIMARY_LITTLE +#define ASI_PRIMARY_LITTLE 0x88 +#endif + +static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, + int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_RS2(rs2)); +} + +static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1, + uint32_t offset, int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | + INSN_IMM13(offset)); +} + +static void tcg_out_arithc(TCGContext *s, int rd, int rs1, + int val2, int val2const, int op) +{ + tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) + | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2))); +} + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR); +} + +static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10)); +} + +static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg) +{ + tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR); +} + +static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg) +{ + if (check_fit_tl(arg, 13)) + tcg_out_movi_imm13(s, ret, arg); + else { + tcg_out_sethi(s, ret, arg); + if (arg & 0x3ff) + tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR); + } +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + /* All 32-bit constants, as well as 64-bit constants with + no high bits set go through movi_imm32. */ + if (TCG_TARGET_REG_BITS == 32 + || type == TCG_TYPE_I32 + || (arg & ~(tcg_target_long)0xffffffff) == 0) { + tcg_out_movi_imm32(s, ret, arg); + } else if (check_fit_tl(arg, 13)) { + /* A 13-bit constant sign-extended to 64-bits. */ + tcg_out_movi_imm13(s, ret, arg); + } else if (check_fit_tl(arg, 32)) { + /* A 32-bit constant sign-extended to 64-bits. */ + tcg_out_sethi(s, ret, ~arg); + tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR); + } else { + tcg_out_movi_imm32(s, TCG_REG_I4, arg >> (TCG_TARGET_REG_BITS / 2)); + tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX); + tcg_out_movi_imm32(s, ret, arg); + tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR); + } +} + +static inline void tcg_out_ld_raw(TCGContext *s, int ret, + tcg_target_long arg) +{ + tcg_out_sethi(s, ret, arg); + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); +} + +static inline void tcg_out_ld_ptr(TCGContext *s, int ret, + tcg_target_long arg) +{ + if (!check_fit_tl(arg, 10)) + tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL); + if (TCG_TARGET_REG_BITS == 64) { + tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); + } else { + tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | + INSN_IMM13(arg & 0x3ff)); + } +} + +static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op) +{ + if (check_fit_tl(offset, 13)) + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | + INSN_IMM13(offset)); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(addr)); + } +} + +static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr, + int offset, int op, int asi) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | + INSN_ASI(asi) | INSN_RS2(addr)); +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, ret, arg1, arg2, LDUW); + else + tcg_out_ldst(s, ret, arg1, arg2, LDX); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_ldst(s, arg, arg1, arg2, STW); + else + tcg_out_ldst(s, arg, arg1, arg2, STX); +} + +static inline void tcg_out_sety(TCGContext *s, int rs) +{ + tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); +} + +static inline void tcg_out_rdy(TCGContext *s, int rd) +{ + tcg_out32(s, RDY | INSN_RD(rd)); +} + +static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); + } + } +} + +static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) { + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_AND); + else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND); + } + } +} + +static void tcg_out_div32(TCGContext *s, int rd, int rs1, + int val2, int val2const, int uns) +{ + /* Load Y with the sign/zero extension of RS1 to 64-bits. */ + if (uns) { + tcg_out_sety(s, TCG_REG_G0); + } else { + tcg_out_arithi(s, TCG_REG_I5, rs1, 31, SHIFT_SRA); + tcg_out_sety(s, TCG_REG_I5); + } + + tcg_out_arithc(s, rd, rs1, val2, val2const, + uns ? ARITH_UDIV : ARITH_SDIV); +} + +static inline void tcg_out_nop(TCGContext *s) +{ + tcg_out_sethi(s, TCG_REG_G0, 0); +} + +static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) + | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); + } +} + +#if TCG_TARGET_REG_BITS == 64 +static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | + INSN_OFF19(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | 0)); + } +} +#endif + +static const uint8_t tcg_cond_to_bcond[10] = { + [TCG_COND_EQ] = COND_E, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_L, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_G, + [TCG_COND_LTU] = COND_CS, + [TCG_COND_GEU] = COND_CC, + [TCG_COND_LEU] = COND_LEU, + [TCG_COND_GTU] = COND_GU, +}; + +static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const) +{ + tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC); +} + +static void tcg_out_brcond_i32(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp(s, arg1, arg2, const_arg2); + tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} + +#if TCG_TARGET_REG_BITS == 64 +static void tcg_out_brcond_i64(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + tcg_out_cmp(s, arg1, arg2, const_arg2); + tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} +#else +static void tcg_out_brcond2_i32(TCGContext *s, int cond, + TCGArg al, TCGArg ah, + TCGArg bl, int blconst, + TCGArg bh, int bhconst, int label_dest) +{ + int cc, label_next = gen_new_label(); + + tcg_out_cmp(s, ah, bh, bhconst); + + /* Note that we fill one of the delay slots with the second compare. */ + switch (cond) { + case TCG_COND_EQ: + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_next); + tcg_out_cmp(s, al, bl, blconst); + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_EQ], 0); + tcg_out_branch_i32(s, cc, label_dest); + break; + + case TCG_COND_NE: + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_dest); + tcg_out_cmp(s, al, bl, blconst); + tcg_out_branch_i32(s, cc, label_dest); + break; + + default: + /* ??? One could fairly easily special-case 64-bit unsigned + compares against 32-bit zero-extended constants. For instance, + we know that (unsigned)AH < 0 is false and need not emit it. + Similarly, (unsigned)AH > 0 being true implies AH != 0, so the + second branch will never be taken. */ + cc = INSN_COND(tcg_cond_to_bcond[cond], 0); + tcg_out_branch_i32(s, cc, label_dest); + tcg_out_nop(s); + cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); + tcg_out_branch_i32(s, cc, label_next); + tcg_out_cmp(s, al, bl, blconst); + cc = INSN_COND(tcg_cond_to_bcond[tcg_unsigned_cond(cond)], 0); + tcg_out_branch_i32(s, cc, label_dest); + break; + } + tcg_out_nop(s); + + tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); +} +#endif + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | + INSN_IMM13(-TCG_TARGET_STACK_MINFRAME)); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) | + INSN_RS2(TCG_REG_G0)); + tcg_out_nop(s); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static const void * const qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static const void * const qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +#if TARGET_LONG_BITS == 32 +#define TARGET_LD_OP LDUW +#else +#define TARGET_LD_OP LDX +#endif + +#if TARGET_PHYS_ADDR_BITS == 32 +#define TARGET_ADDEND_LD_OP LDUW +#else +#define TARGET_ADDEND_LD_OP LDX +#endif + +#ifdef __arch64__ +#define HOST_LD_OP LDX +#define HOST_ST_OP STX +#define HOST_SLL_OP SHIFT_SLLX +#define HOST_SRA_OP SHIFT_SRAX +#else +#define HOST_LD_OP LDUW +#define HOST_ST_OP STW +#define HOST_SLL_OP SHIFT_SLL +#define HOST_SRA_OP SHIFT_SRA +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_read)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 + or + be,pt %xcc label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_ld_helper[s_bits](arg0, arg1) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + + /* data_reg = sign_extend(arg0) */ + switch(opc) { + case 0 | 4: + /* sll arg0, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8, + HOST_SLL_OP); + /* sra data_reg, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP); + break; + case 1 | 4: + /* sll arg0, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, arg0, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP); + /* sra data_reg, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, + (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP); + break; + case 2 | 4: + /* sll arg0, 32, data_reg */ + tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP); + /* sra data_reg, 32, data_reg */ + tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP); + break; + case 0: + case 1: + case 2: + case 3: + default: + /* mov */ + tcg_out_mov(s, data_reg, arg0); + break; + } + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot */ + tcg_out_nop(s); + + /* label1: */ +#if TARGET_LONG_BITS == 32 + /* be label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* ldub [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUB); + break; + case 0 | 4: + /* ldsb [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUH); +#else + /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 1 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsh [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSH); +#else + /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* lduw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDUW); +#else + /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2 | 4: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldsw [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDSW); +#else + /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* ldx [arg0], data_reg */ + tcg_out_ldst(s, data_reg, arg0, 0, LDX); +#else + /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; +#if defined(CONFIG_SOFTMMU) + uint32_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + arg0 = TCG_REG_O0; + arg1 = TCG_REG_O1; + arg2 = TCG_REG_O2; + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, arg1 */ + tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + + /* and addr_reg, x, arg0 */ + tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and arg1, x, arg1 */ + tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* add arg1, x, arg1 */ + tcg_out_addi(s, arg1, offsetof(CPUState, + tlb_table[mem_index][0].addr_write)); + + /* add env, arg1, arg1 */ + tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); + + /* ld [arg1], arg2 */ + tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | + INSN_RS2(TCG_REG_G0)); + + /* subcc arg0, arg2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); + + /* will become: + be label1 + or + be,pt %xcc label1 */ + label1_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot) */ + tcg_out_mov(s, arg0, addr_reg); + + /* mov */ + tcg_out_mov(s, arg1, data_reg); + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); + + /* XXX: move that code at the end of the TB */ + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + + /* will become: + ba label2 */ + label2_ptr = (uint32_t *)s->code_ptr; + tcg_out32(s, 0); + + /* nop (delay slot) */ + tcg_out_nop(s); + +#if TARGET_LONG_BITS == 32 + /* be label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif + + /* ld [arg1 + x], arg1 */ + tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP); + +#if TARGET_LONG_BITS == 32 + /* and addr_reg, x, arg0 */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); + tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); + /* add arg0, arg1, arg0 */ + tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); +#else + /* add addr_reg, arg1, arg0 */ + tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +#endif + +#else + arg0 = addr_reg; +#endif + + switch(opc) { + case 0: + /* stb data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STB); + break; + case 1: +#ifdef TARGET_WORDS_BIGENDIAN + /* sth data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STH); +#else + /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE); +#endif + break; + case 2: +#ifdef TARGET_WORDS_BIGENDIAN + /* stw data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STW); +#else + /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE); +#endif + break; + case 3: +#ifdef TARGET_WORDS_BIGENDIAN + /* stx data_reg, [arg0] */ + tcg_out_ldst(s, data_reg, arg0, 0, STX); +#else + /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */ + tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE); +#endif + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)s->code_ptr - + (unsigned long)label2_ptr)); +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) | + INSN_IMM13(8)); + tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) | + INSN_RS2(TCG_REG_G0)); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_IMM13((args[0] & 0x1fff))); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) + tcg_out32(s, CALL | ((((tcg_target_ulong)args[0] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + else { + tcg_out_ld_ptr(s, TCG_REG_I5, + (tcg_target_long)(s->tb_next + args[0])); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); + tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); + break; + case INDEX_op_jmp: + case INDEX_op_br: + tcg_out_branch_i32(s, COND_A, args[0]); + tcg_out_nop(s); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + +#if TCG_TARGET_REG_BITS == 64 +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32): \ + glue(glue(case INDEX_op_, x), _i64) +#else +#define OP_32_64(x) \ + glue(glue(case INDEX_op_, x), _i32) +#endif + OP_32_64(ld8u): + tcg_out_ldst(s, args[0], args[1], args[2], LDUB); + break; + OP_32_64(ld8s): + tcg_out_ldst(s, args[0], args[1], args[2], LDSB); + break; + OP_32_64(ld16u): + tcg_out_ldst(s, args[0], args[1], args[2], LDUH); + break; + OP_32_64(ld16s): + tcg_out_ldst(s, args[0], args[1], args[2], LDSH); + break; + case INDEX_op_ld_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_ld32u_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], LDUW); + break; + OP_32_64(st8): + tcg_out_ldst(s, args[0], args[1], args[2], STB); + break; + OP_32_64(st16): + tcg_out_ldst(s, args[0], args[1], args[2], STH); + break; + case INDEX_op_st_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_st32_i64: +#endif + tcg_out_ldst(s, args[0], args[1], args[2], STW); + break; + OP_32_64(add): + c = ARITH_ADD; + goto gen_arith; + OP_32_64(sub): + c = ARITH_SUB; + goto gen_arith; + OP_32_64(and): + c = ARITH_AND; + goto gen_arith; + OP_32_64(or): + c = ARITH_OR; + goto gen_arith; + OP_32_64(xor): + c = ARITH_XOR; + goto gen_arith; + case INDEX_op_shl_i32: + c = SHIFT_SLL; + goto gen_arith; + case INDEX_op_shr_i32: + c = SHIFT_SRL; + goto gen_arith; + case INDEX_op_sar_i32: + c = SHIFT_SRA; + goto gen_arith; + case INDEX_op_mul_i32: + c = ARITH_UMUL; + goto gen_arith; + + case INDEX_op_div_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0); + break; + case INDEX_op_divu_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1); + break; + + case INDEX_op_rem_i32: + case INDEX_op_remu_i32: + tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_remu_i32); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_UMUL); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; + + case INDEX_op_brcond_i32: + tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; +#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_brcond2_i32: + tcg_out_brcond2_i32(s, args[4], args[0], args[1], + args[2], const_args[2], + args[3], const_args[3], args[5]); + break; + case INDEX_op_add2_i32: + tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], + ARITH_ADDCC); + tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], + ARITH_ADDX); + break; + case INDEX_op_sub2_i32: + tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], + ARITH_SUBCC); + tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], + ARITH_SUBX); + break; + case INDEX_op_mulu2_i32: + tcg_out_arithc(s, args[0], args[2], args[3], const_args[3], + ARITH_UMUL); + tcg_out_rdy(s, args[1]); + break; +#endif + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld32s_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDSW); + break; + case INDEX_op_ld_i64: + tcg_out_ldst(s, args[0], args[1], args[2], LDX); + break; + case INDEX_op_st_i64: + tcg_out_ldst(s, args[0], args[1], args[2], STX); + break; + case INDEX_op_shl_i64: + c = SHIFT_SLLX; + goto gen_arith; + case INDEX_op_shr_i64: + c = SHIFT_SRLX; + goto gen_arith; + case INDEX_op_sar_i64: + c = SHIFT_SRAX; + goto gen_arith; + case INDEX_op_mul_i64: + c = ARITH_MULX; + goto gen_arith; + case INDEX_op_div_i64: + c = ARITH_SDIVX; + goto gen_arith; + case INDEX_op_divu_i64: + c = ARITH_UDIVX; + goto gen_arith; + case INDEX_op_rem_i64: + case INDEX_op_remu_i64: + tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_MULX); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; + case INDEX_op_ext32s_i64: + if (const_args[1]) { + tcg_out_movi(s, TCG_TYPE_I64, args[0], (int32_t)args[1]); + } else { + tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA); + } + break; + case INDEX_op_ext32u_i64: + if (const_args[1]) { + tcg_out_movi_imm32(s, args[0], args[1]); + } else { + tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL); + } + break; + + case INDEX_op_brcond_i64: + tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1], + args[3]); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + +#endif + gen_arith: + tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c); + break; + + default: + fprintf(stderr, "unknown opcode 0x%x\n", opc); + tcg_abort(); + } +} + +static const TCGTargetOpDef sparc_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "rJ" } }, + { INDEX_op_mul_i32, { "r", "r", "rJ" } }, + { INDEX_op_div_i32, { "r", "r", "rJ" } }, + { INDEX_op_divu_i32, { "r", "r", "rJ" } }, + { INDEX_op_rem_i32, { "r", "r", "rJ" } }, + { INDEX_op_remu_i32, { "r", "r", "rJ" } }, + { INDEX_op_sub_i32, { "r", "r", "rJ" } }, + { INDEX_op_and_i32, { "r", "r", "rJ" } }, + { INDEX_op_or_i32, { "r", "r", "rJ" } }, + { INDEX_op_xor_i32, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i32, { "r", "r", "rJ" } }, + { INDEX_op_shr_i32, { "r", "r", "rJ" } }, + { INDEX_op_sar_i32, { "r", "r", "rJ" } }, + + { INDEX_op_brcond_i32, { "r", "rJ" } }, +#if TCG_TARGET_REG_BITS == 32 + { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } }, + { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, + { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } }, +#endif + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + +#if TCG_TARGET_REG_BITS == 64 + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + { INDEX_op_qemu_ld64, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L" } }, + + { INDEX_op_add_i64, { "r", "r", "rJ" } }, + { INDEX_op_mul_i64, { "r", "r", "rJ" } }, + { INDEX_op_div_i64, { "r", "r", "rJ" } }, + { INDEX_op_divu_i64, { "r", "r", "rJ" } }, + { INDEX_op_rem_i64, { "r", "r", "rJ" } }, + { INDEX_op_remu_i64, { "r", "r", "rJ" } }, + { INDEX_op_sub_i64, { "r", "r", "rJ" } }, + { INDEX_op_and_i64, { "r", "r", "rJ" } }, + { INDEX_op_or_i64, { "r", "r", "rJ" } }, + { INDEX_op_xor_i64, { "r", "r", "rJ" } }, + + { INDEX_op_shl_i64, { "r", "r", "rJ" } }, + { INDEX_op_shr_i64, { "r", "r", "rJ" } }, + { INDEX_op_sar_i64, { "r", "r", "rJ" } }, + { INDEX_op_ext32s_i64, { "r", "ri" } }, + { INDEX_op_ext32u_i64, { "r", "ri" } }, + + { INDEX_op_brcond_i64, { "r", "rJ" } }, +#endif + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); +#if TCG_TARGET_REG_BITS == 64 + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); +#endif + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_G1) | + (1 << TCG_REG_G2) | + (1 << TCG_REG_G3) | + (1 << TCG_REG_G4) | + (1 << TCG_REG_G5) | + (1 << TCG_REG_G6) | + (1 << TCG_REG_G7) | + (1 << TCG_REG_O0) | + (1 << TCG_REG_O1) | + (1 << TCG_REG_O2) | + (1 << TCG_REG_O3) | + (1 << TCG_REG_O4) | + (1 << TCG_REG_O5) | + (1 << TCG_REG_O7)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); +#if TCG_TARGET_REG_BITS == 64 + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use +#endif + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7); + tcg_add_target_add_op_defs(sparc_op_defs); +} diff --git a/qemu/qemu-git/tcg/sparc/tcg-target.h b/qemu/qemu-git/tcg/sparc/tcg-target.h new file mode 100644 index 0000000..d27ed5a --- /dev/null +++ b/qemu/qemu-git/tcg/sparc/tcg-target.h @@ -0,0 +1,129 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_SPARC 1 + +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +#define TCG_TARGET_REG_BITS 64 +#else +#define TCG_TARGET_REG_BITS 32 +#endif + +#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 32 + +enum { + TCG_REG_G0 = 0, + TCG_REG_G1, + TCG_REG_G2, + TCG_REG_G3, + TCG_REG_G4, + TCG_REG_G5, + TCG_REG_G6, + TCG_REG_G7, + TCG_REG_O0, + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, + TCG_REG_O4, + TCG_REG_O5, + TCG_REG_O6, + TCG_REG_O7, + TCG_REG_L0, + TCG_REG_L1, + TCG_REG_L2, + TCG_REG_L3, + TCG_REG_L4, + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, + TCG_REG_I5, + TCG_REG_I6, + TCG_REG_I7, +}; + +#define TCG_CT_CONST_S11 0x100 +#define TCG_CT_CONST_S13 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_I6 +#ifdef __arch64__ +// Reserve space for AREG0 +#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16) +#define TCG_TARGET_STACK_ALIGN 16 +#else +// AREG0 + one word for alignment +#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME +#define TCG_TARGET_STACK_ALIGN 8 +#endif + +/* optional instructions */ +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_div_i64 + +#if TCG_TARGET_REG_BITS == 64 +#define TCG_TARGET_HAS_ext32s_i64 +#define TCG_TARGET_HAS_ext32u_i64 +#endif + +//#define TCG_TARGET_HAS_bswap32_i32 +//#define TCG_TARGET_HAS_bswap64_i64 +//#define TCG_TARGET_HAS_neg_i32 +//#define TCG_TARGET_HAS_neg_i64 + + +/* Note: must be synced with dyngen-exec.h and Makefile.target */ +#ifdef CONFIG_SOLARIS +#define TCG_AREG0 TCG_REG_G2 +#define TCG_AREG1 TCG_REG_G3 +#define TCG_AREG2 TCG_REG_G4 +#elif defined(__sparc_v9__) +#define TCG_AREG0 TCG_REG_G5 +#define TCG_AREG1 TCG_REG_G6 +#define TCG_AREG2 TCG_REG_G7 +#else +#define TCG_AREG0 TCG_REG_G6 +#define TCG_AREG1 TCG_REG_G1 +#define TCG_AREG2 TCG_REG_G2 +#endif + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(8UL - 1UL); + stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); + + for (; p < stop; p += 8) + __asm__ __volatile__("flush\t%0" : : "r" (p)); +} diff --git a/qemu/qemu-git/tcg/tcg-op.h b/qemu/qemu-git/tcg/tcg-op.h new file mode 100644 index 0000000..faf2e8b --- /dev/null +++ b/qemu/qemu-git/tcg/tcg-op.h @@ -0,0 +1,2183 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "tcg.h" + +int gen_new_label(void); + +static inline void tcg_gen_op1_i32(int opc, TCGv_i32 arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); +} + +static inline void tcg_gen_op1_i64(int opc, TCGv_i64 arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); +} + +static inline void tcg_gen_op1i(int opc, TCGArg arg1) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; +} + +static inline void tcg_gen_op2_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); +} + +static inline void tcg_gen_op2_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); +} + +static inline void tcg_gen_op2i_i32(int opc, TCGv_i32 arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op2i_i64(int opc, TCGv_i64 arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op2ii(int opc, TCGArg arg1, TCGArg arg2) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = arg1; + *gen_opparam_ptr++ = arg2; +} + +static inline void tcg_gen_op3_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); +} + +static inline void tcg_gen_op3_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); +} + +static inline void tcg_gen_op3i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGArg arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = arg3; +} + +static inline void tcg_gen_op3i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGArg arg3) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = arg3; +} + +static inline void tcg_gen_ldst_op_i32(int opc, TCGv_i32 val, TCGv_ptr base, + TCGArg offset) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(val); + *gen_opparam_ptr++ = GET_TCGV_PTR(base); + *gen_opparam_ptr++ = offset; +} + +static inline void tcg_gen_ldst_op_i64(int opc, TCGv_i64 val, TCGv_ptr base, + TCGArg offset) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_PTR(base); + *gen_opparam_ptr++ = offset; +} + +static inline void tcg_gen_qemu_ldst_op_i64_i32(int opc, TCGv_i64 val, TCGv_i32 addr, + TCGArg mem_index) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_I32(addr); + *gen_opparam_ptr++ = mem_index; +} + +static inline void tcg_gen_qemu_ldst_op_i64_i64(int opc, TCGv_i64 val, TCGv_i64 addr, + TCGArg mem_index) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(val); + *gen_opparam_ptr++ = GET_TCGV_I64(addr); + *gen_opparam_ptr++ = mem_index; +} + +static inline void tcg_gen_op4_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); +} + +static inline void tcg_gen_op4_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); +} + +static inline void tcg_gen_op4i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGArg arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = arg3; + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op4ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGArg arg3, TCGArg arg4) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = arg3; + *gen_opparam_ptr++ = arg4; +} + +static inline void tcg_gen_op5_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = GET_TCGV_I32(arg5); +} + +static inline void tcg_gen_op5_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = GET_TCGV_I64(arg5); +} + +static inline void tcg_gen_op5i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = arg5; +} + +static inline void tcg_gen_op5i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = arg5; +} + +static inline void tcg_gen_op6_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5, + TCGv_i32 arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = GET_TCGV_I32(arg5); + *gen_opparam_ptr++ = GET_TCGV_I32(arg6); +} + +static inline void tcg_gen_op6_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5, + TCGv_i64 arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = GET_TCGV_I64(arg5); + *gen_opparam_ptr++ = GET_TCGV_I64(arg6); +} + +static inline void tcg_gen_op6ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2, + TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5, + TCGArg arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *gen_opparam_ptr++ = arg5; + *gen_opparam_ptr++ = arg6; +} + +static inline void tcg_gen_op6ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5, + TCGArg arg6) +{ + *gen_opc_ptr++ = opc; + *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *gen_opparam_ptr++ = arg5; + *gen_opparam_ptr++ = arg6; +} + +static inline void gen_set_label(int n) +{ + tcg_gen_op1i(INDEX_op_set_label, n); +} + +static inline void tcg_gen_br(int label) +{ + tcg_gen_op1i(INDEX_op_br, label); +} + +static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + if (!TCGV_EQUAL_I32(ret, arg)) + tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg); +} + +static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg) +{ + tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg); +} + +/* helper calls */ +static inline void tcg_gen_helperN(void *func, int flags, int sizemask, + TCGArg ret, int nargs, TCGArg *args) +{ + TCGv_ptr fn; + fn = tcg_const_ptr((tcg_target_long)func); + tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret, + nargs, args); + tcg_temp_free_ptr(fn); +} + +/* FIXME: Should this be pure? */ +static inline void tcg_gen_helper64(void *func, TCGv_i64 ret, + TCGv_i64 a, TCGv_i64 b) +{ + TCGv_ptr fn; + TCGArg args[2]; + fn = tcg_const_ptr((tcg_target_long)func); + args[0] = GET_TCGV_I64(a); + args[1] = GET_TCGV_I64(b); + tcg_gen_callN(&tcg_ctx, fn, 0, 7, GET_TCGV_I64(ret), 2, args); + tcg_temp_free_ptr(fn); +} + +/* 32 bit ops */ + +static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_add_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0 = tcg_const_i32(arg1); + tcg_gen_sub_i32(ret, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_sub_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_movi_i32(ret, 0); + } else if (arg2 == 0xffffffff) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0xffffffff) { + tcg_gen_movi_i32(ret, 0xffffffff); + } else if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCGV_EQUAL_I32(arg1, arg2)) { + tcg_gen_movi_i32(ret, 0); + } else { + tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2); + } +} + +static inline void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_xor_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_shl_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_shr_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_sar_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); + } +} + +static inline void tcg_gen_brcond_i32(int cond, TCGv_i32 arg1, TCGv_i32 arg2, + int label_index) +{ + tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_brcondi_i32(int cond, TCGv_i32 arg1, int32_t arg2, + int label_index) +{ + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_brcond_i32(cond, arg1, t0, label_index); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_mul_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +#ifdef TCG_TARGET_HAS_div_i32 +static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_sari_i32(t0, arg1, 31); + tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, 0); + tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); + tcg_temp_free_i32(t0); +} +#endif + +#if TCG_TARGET_REG_BITS == 32 + +static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + if (!TCGV_EQUAL_I64(ret, arg)) { + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + } +} + +static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) +{ + tcg_gen_movi_i32(TCGV_LOW(ret), arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); +} + +static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), 31); +} + +static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, + tcg_target_long offset) +{ + /* since arg2 and ret have different types, they cannot be the + same temporary */ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); +#else + tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); + tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, + tcg_target_long offset) +{ +#ifdef TCG_TARGET_WORDS_BIGENDIAN + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); +#else + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); + tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); +#endif +} + +static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); + tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); +} + +static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); + tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); +} + +/* XXX: use generic code when basic block handling is OK or CPU + specific code (x86) */ +static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); +} + +static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); +} + +static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, + int label_index) +{ + tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2), cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + TCGv_i32 t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i32(); + + tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0), + TCGV_LOW(arg1), TCGV_LOW(arg2)); + + tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2)); + tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); + + tcg_gen_mov_i64(ret, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i32(t1); +} + +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_helper64(tcg_helper_remu_i64, ret, arg1, arg2); +} + +#else + +static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + if (!TCGV_EQUAL_I64(ret, arg)) + tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg); +} + +static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) +{ + tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg); +} + +static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset); +} + +static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset); +} + +static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2, + tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset) +{ + tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset); +} + +static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCGV_EQUAL_I64(arg1, arg2)) { + tcg_gen_movi_i64(ret, 0); + } else { + tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2); + } +} + +static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_xor_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_shl_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_shr_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_sar_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, + int label_index) +{ + tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); +} + +static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); +} + +#ifdef TCG_TARGET_HAS_div_i64 +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); +} +#else +static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_sari_i64(t0, arg1, 63); + tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, 0); + tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); + tcg_temp_free_i64(t0); +} +#endif + +#endif + +static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_add_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg1); + tcg_gen_sub_i64(ret, t0, arg2); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_sub_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); + } +} +static inline void tcg_gen_brcondi_i64(int cond, TCGv_i64 arg1, int64_t arg2, + int label_index) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_brcond_i64(cond, arg1, t0, label_index); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_mul_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + + +/***************************************/ +/* optional operations */ + +static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i32 + tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 24); + tcg_gen_sari_i32(ret, ret, 24); +#endif +} + +static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i32 + tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); +#else + tcg_gen_shli_i32(ret, arg, 16); + tcg_gen_sari_i32(ret, ret, 16); +#endif +} + +static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext8u_i32 + tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); +#else + tcg_gen_andi_i32(ret, arg, 0xffu); +#endif +} + +static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_ext16u_i32 + tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); +#else + tcg_gen_andi_i32(ret, arg, 0xffffu); +#endif +} + +/* Note: we assume the two high bytes are set to zero */ +static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_bswap16_i32 + tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg); +#else + TCGv_i32 t0 = tcg_temp_new_i32(); + + tcg_gen_ext8u_i32(t0, arg); + tcg_gen_shli_i32(t0, t0, 8); + tcg_gen_shri_i32(ret, arg, 8); + tcg_gen_or_i32(ret, ret, t0); + tcg_temp_free_i32(t0); +#endif +} + +static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_bswap32_i32 + tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg); +#else + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + + tcg_gen_shli_i32(t0, arg, 24); + + tcg_gen_andi_i32(t1, arg, 0x0000ff00); + tcg_gen_shli_i32(t1, t1, 8); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 8); + tcg_gen_andi_i32(t1, t1, 0x0000ff00); + tcg_gen_or_i32(t0, t0, t1); + + tcg_gen_shri_i32(t1, arg, 24); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(ret, TCGV_LOW(arg)); +} + +static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), arg); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + +static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_mov_i32(TCGV_LOW(ret), arg); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +} + +/* Note: we assume the six high bytes are set to zero */ +static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg)); +} + +/* Note: we assume the four high bytes are set to zero */ +static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); + tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg)); +} + +static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + + tcg_gen_bswap32_i32(t0, TCGV_LOW(arg)); + tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg)); + tcg_gen_mov_i32(TCGV_LOW(ret), t1); + tcg_gen_mov_i32(TCGV_HIGH(ret), t0); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +} +#else + +static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext8s_i64 + tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 56); + tcg_gen_sari_i64(ret, ret, 56); +#endif +} + +static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext16s_i64 + tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 48); + tcg_gen_sari_i64(ret, ret, 48); +#endif +} + +static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext32s_i64 + tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); +#else + tcg_gen_shli_i64(ret, arg, 32); + tcg_gen_sari_i64(ret, ret, 32); +#endif +} + +static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext8u_i64 + tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffu); +#endif +} + +static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext16u_i64 + tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffffu); +#endif +} + +static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_ext32u_i64 + tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); +#else + tcg_gen_andi_i64(ret, arg, 0xffffffffu); +#endif +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers. This will probably break MIPS64 targets. */ +static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg) +{ + tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg))); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_ext32u_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg))); +} + +/* Note: we assume the target supports move between 32 and 64 bit + registers */ +static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_gen_ext32s_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg))); +} + +/* Note: we assume the six high bytes are set to zero */ +static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap16_i64 + tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ext8u_i64(t0, arg); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(ret, arg, 8); + tcg_gen_or_i64(ret, ret, t0); + tcg_temp_free_i64(t0); +#endif +} + +/* Note: we assume the four high bytes are set to zero */ +static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap32_i64 + tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg); +#else + TCGv_i64 t0, t1; + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_shli_i64(t0, arg, 24); + tcg_gen_ext32u_i64(t0, t0); + + tcg_gen_andi_i64(t1, arg, 0x0000ff00); + tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 8); + tcg_gen_andi_i64(t1, t1, 0x0000ff00); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 24); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_bswap64_i64 + tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_shli_i64(t0, arg, 56); + + tcg_gen_andi_i64(t1, arg, 0x0000ff00); + tcg_gen_shli_i64(t1, t1, 40); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0x00ff0000); + tcg_gen_shli_i64(t1, t1, 24); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_andi_i64(t1, arg, 0xff000000); + tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 8); + tcg_gen_andi_i64(t1, t1, 0xff000000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 24); + tcg_gen_andi_i64(t1, t1, 0x00ff0000); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 40); + tcg_gen_andi_i64(t1, t1, 0x0000ff00); + tcg_gen_or_i64(t0, t0, t1); + + tcg_gen_shri_i64(t1, arg, 56); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +#endif + +static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_neg_i32 + tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg); +#else + TCGv_i32 t0 = tcg_const_i32(0); + tcg_gen_sub_i32(ret, t0, arg); + tcg_temp_free_i32(t0); +#endif +} + +static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_neg_i64 + tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg); +#else + TCGv_i64 t0 = tcg_const_i64(0); + tcg_gen_sub_i64(ret, t0, arg); + tcg_temp_free_i64(t0); +#endif +} + +static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg) +{ +#ifdef TCG_TARGET_HAS_not_i32 + tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg); +#else + tcg_gen_xori_i32(ret, arg, -1); +#endif +} + +static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) +{ +#ifdef TCG_TARGET_HAS_not_i64 + tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); +#else + tcg_gen_xori_i64(ret, arg, -1); +#endif +} + +static inline void tcg_gen_discard_i32(TCGv_i32 arg) +{ + tcg_gen_op1_i32(INDEX_op_discard, arg); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_discard_i64(TCGv_i64 arg) +{ + tcg_gen_discard_i32(TCGV_LOW(arg)); + tcg_gen_discard_i32(TCGV_HIGH(arg)); +} +#else +static inline void tcg_gen_discard_i64(TCGv_i64 arg) +{ + tcg_gen_op1_i64(INDEX_op_discard, arg); +} +#endif + +static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_mov_i32(TCGV_LOW(dest), low); + tcg_gen_mov_i32(TCGV_HIGH(dest), high); +#else + TCGv_i64 tmp = tcg_temp_new_i64(); + /* This extension is only needed for type correctness. + We may be able to do better given target specific information. */ + tcg_gen_extu_i32_i64(tmp, high); + tcg_gen_shli_i64(tmp, tmp, 32); + tcg_gen_extu_i32_i64(dest, low); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free_i64(tmp); +#endif +} + +static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 high) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_concat_i32_i64(dest, TCGV_LOW(low), TCGV_LOW(high)); +#else + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(dest, low); + tcg_gen_shli_i64(tmp, high, 32); + tcg_gen_or_i64(dest, dest, tmp); + tcg_temp_free_i64(tmp); +#endif +} + +static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_not_i32(t0, arg2); + tcg_gen_and_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, arg2); + tcg_gen_and_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_xor_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_xor_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_and_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_and_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_or_i32(ret, arg1, arg2); + tcg_gen_not_i32(ret, ret); +} + +static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_or_i64(ret, arg1, arg2); + tcg_gen_not_i64(ret, ret); +} + +static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_not_i32(t0, arg2); + tcg_gen_or_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} + +static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, arg2); + tcg_gen_or_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +} + +static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i32 + tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); +#else + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shl_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shr_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i64 + tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); +#else + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shl_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shr_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { +#ifdef TCG_TARGET_HAS_rot_i32 + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_rotl_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +#else + TCGv_i32 t0, t1; + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shli_i32(t0, arg1, arg2); + tcg_gen_shri_i32(t1, arg1, 32 - arg2); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif + } +} + +static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { +#ifdef TCG_TARGET_HAS_rot_i64 + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_rotl_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); +#else + TCGv_i64 t0, t1; + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t0, arg1, arg2); + tcg_gen_shri_i64(t1, arg1, 64 - arg2); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif + } +} + +static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i32 + tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); +#else + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + tcg_gen_shr_i32(t0, arg1, arg2); + tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_shl_i32(t1, arg1, t1); + tcg_gen_or_i32(ret, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +#endif +} + +static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ +#ifdef TCG_TARGET_HAS_rot_i64 + tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); +#else + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_shr_i64(t0, arg1, arg2); + tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_shl_i64(t1, arg1, t1); + tcg_gen_or_i64(ret, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +#endif +} + +static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i32(ret, arg1); + } else { + tcg_gen_rotli_i32(ret, arg1, 32 - arg2); + } +} + +static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) +{ + /* some cases can be optimized here */ + if (arg2 == 0) { + tcg_gen_mov_i64(ret, arg1); + } else { + tcg_gen_rotli_i64(ret, arg1, 64 - arg2); + } +} + +/***************************************/ +/* QEMU specific operations. Their type depend on the QEMU CPU + type. */ +#ifndef TARGET_LONG_BITS +#error must include QEMU headers +#endif + +#if TARGET_LONG_BITS == 32 +#define TCGv TCGv_i32 +#define tcg_temp_new() tcg_temp_new_i32() +#define tcg_global_reg_new tcg_global_reg_new_i32 +#define tcg_global_mem_new tcg_global_mem_new_i32 +#define tcg_temp_local_new() tcg_temp_local_new_i32() +#define tcg_temp_free tcg_temp_free_i32 +#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32 +#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32 +#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x) +#define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b) +#else +#define TCGv TCGv_i64 +#define tcg_temp_new() tcg_temp_new_i64() +#define tcg_global_reg_new tcg_global_reg_new_i64 +#define tcg_global_mem_new tcg_global_mem_new_i64 +#define tcg_temp_local_new() tcg_temp_local_new_i64() +#define tcg_temp_free tcg_temp_free_i64 +#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64 +#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64 +#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x) +#define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b) +#endif + +/* debug info: write the PC of the corresponding QEMU CPU instruction */ +static inline void tcg_gen_debug_insn_start(uint64_t pc) +{ + /* XXX: must really use a 32 bit size for TCGArg in all cases */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + tcg_gen_op2ii(INDEX_op_debug_insn_start, + (uint32_t)(pc), (uint32_t)(pc >> 32)); +#else + tcg_gen_op1i(INDEX_op_debug_insn_start, pc); +#endif +} + +static inline void tcg_gen_exit_tb(tcg_target_long val) +{ + tcg_gen_op1i(INDEX_op_exit_tb, val); +} + +static inline void tcg_gen_goto_tb(int idx) +{ + tcg_gen_op1i(INDEX_op_goto_tb, idx); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld8u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld8u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld8s, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld8s, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld16u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld16u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld16s, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld16s, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +#endif +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); +#endif +} + +static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), addr, mem_index); +#else + tcg_gen_op5i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), + TCGV_LOW(addr), TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st8, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st8, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st16, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st16, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op3i_i32(INDEX_op_qemu_st32, arg, addr, mem_index); +#else + tcg_gen_op4i_i32(INDEX_op_qemu_st32, TCGV_LOW(arg), TCGV_LOW(addr), + TCGV_HIGH(addr), mem_index); +#endif +} + +static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) +{ +#if TARGET_LONG_BITS == 32 + tcg_gen_op4i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), addr, + mem_index); +#else + tcg_gen_op5i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), + TCGV_LOW(addr), TCGV_HIGH(addr), mem_index); +#endif +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i32 +#define tcg_gen_discard_ptr tcg_gen_discard_i32 + +#else /* TCG_TARGET_REG_BITS == 32 */ + +static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32u, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32s, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_ld64, ret, addr, mem_index); +} + +static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st8, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st16, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op(INDEX_op_qemu_st32, arg, addr, mem_index); +} + +static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) +{ + tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index); +} + +#define tcg_gen_ld_ptr tcg_gen_ld_i64 +#define tcg_gen_discard_ptr tcg_gen_discard_i64 + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#if TARGET_LONG_BITS == 64 +#define TCG_TYPE_TL TCG_TYPE_I64 +#define tcg_gen_movi_tl tcg_gen_movi_i64 +#define tcg_gen_mov_tl tcg_gen_mov_i64 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i64 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i64 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i64 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i64 +#define tcg_gen_ld32u_tl tcg_gen_ld32u_i64 +#define tcg_gen_ld32s_tl tcg_gen_ld32s_i64 +#define tcg_gen_ld_tl tcg_gen_ld_i64 +#define tcg_gen_st8_tl tcg_gen_st8_i64 +#define tcg_gen_st16_tl tcg_gen_st16_i64 +#define tcg_gen_st32_tl tcg_gen_st32_i64 +#define tcg_gen_st_tl tcg_gen_st_i64 +#define tcg_gen_add_tl tcg_gen_add_i64 +#define tcg_gen_addi_tl tcg_gen_addi_i64 +#define tcg_gen_sub_tl tcg_gen_sub_i64 +#define tcg_gen_neg_tl tcg_gen_neg_i64 +#define tcg_gen_subfi_tl tcg_gen_subfi_i64 +#define tcg_gen_subi_tl tcg_gen_subi_i64 +#define tcg_gen_and_tl tcg_gen_and_i64 +#define tcg_gen_andi_tl tcg_gen_andi_i64 +#define tcg_gen_or_tl tcg_gen_or_i64 +#define tcg_gen_ori_tl tcg_gen_ori_i64 +#define tcg_gen_xor_tl tcg_gen_xor_i64 +#define tcg_gen_xori_tl tcg_gen_xori_i64 +#define tcg_gen_not_tl tcg_gen_not_i64 +#define tcg_gen_shl_tl tcg_gen_shl_i64 +#define tcg_gen_shli_tl tcg_gen_shli_i64 +#define tcg_gen_shr_tl tcg_gen_shr_i64 +#define tcg_gen_shri_tl tcg_gen_shri_i64 +#define tcg_gen_sar_tl tcg_gen_sar_i64 +#define tcg_gen_sari_tl tcg_gen_sari_i64 +#define tcg_gen_brcond_tl tcg_gen_brcond_i64 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i64 +#define tcg_gen_mul_tl tcg_gen_mul_i64 +#define tcg_gen_muli_tl tcg_gen_muli_i64 +#define tcg_gen_div_tl tcg_gen_div_i64 +#define tcg_gen_rem_tl tcg_gen_rem_i64 +#define tcg_gen_divu_tl tcg_gen_divu_i64 +#define tcg_gen_remu_tl tcg_gen_remu_i64 +#define tcg_gen_discard_tl tcg_gen_discard_i64 +#define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_mov_i64 +#define tcg_gen_extu_i32_tl tcg_gen_extu_i32_i64 +#define tcg_gen_ext_i32_tl tcg_gen_ext_i32_i64 +#define tcg_gen_extu_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_mov_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i64 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i64 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i64 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i64 +#define tcg_gen_ext32u_tl tcg_gen_ext32u_i64 +#define tcg_gen_ext32s_tl tcg_gen_ext32s_i64 +#define tcg_gen_bswap16_tl tcg_gen_bswap16_i64 +#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64 +#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64 +#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i64 +#define tcg_gen_eqv_tl tcg_gen_eqv_i64 +#define tcg_gen_nand_tl tcg_gen_nand_i64 +#define tcg_gen_nor_tl tcg_gen_nor_i64 +#define tcg_gen_orc_tl tcg_gen_orc_i64 +#define tcg_gen_rotl_tl tcg_gen_rotl_i64 +#define tcg_gen_rotli_tl tcg_gen_rotli_i64 +#define tcg_gen_rotr_tl tcg_gen_rotr_i64 +#define tcg_gen_rotri_tl tcg_gen_rotri_i64 +#define tcg_const_tl tcg_const_i64 +#define tcg_const_local_tl tcg_const_local_i64 +#else +#define TCG_TYPE_TL TCG_TYPE_I32 +#define tcg_gen_movi_tl tcg_gen_movi_i32 +#define tcg_gen_mov_tl tcg_gen_mov_i32 +#define tcg_gen_ld8u_tl tcg_gen_ld8u_i32 +#define tcg_gen_ld8s_tl tcg_gen_ld8s_i32 +#define tcg_gen_ld16u_tl tcg_gen_ld16u_i32 +#define tcg_gen_ld16s_tl tcg_gen_ld16s_i32 +#define tcg_gen_ld32u_tl tcg_gen_ld_i32 +#define tcg_gen_ld32s_tl tcg_gen_ld_i32 +#define tcg_gen_ld_tl tcg_gen_ld_i32 +#define tcg_gen_st8_tl tcg_gen_st8_i32 +#define tcg_gen_st16_tl tcg_gen_st16_i32 +#define tcg_gen_st32_tl tcg_gen_st_i32 +#define tcg_gen_st_tl tcg_gen_st_i32 +#define tcg_gen_add_tl tcg_gen_add_i32 +#define tcg_gen_addi_tl tcg_gen_addi_i32 +#define tcg_gen_sub_tl tcg_gen_sub_i32 +#define tcg_gen_neg_tl tcg_gen_neg_i32 +#define tcg_gen_subfi_tl tcg_gen_subfi_i32 +#define tcg_gen_subi_tl tcg_gen_subi_i32 +#define tcg_gen_and_tl tcg_gen_and_i32 +#define tcg_gen_andi_tl tcg_gen_andi_i32 +#define tcg_gen_or_tl tcg_gen_or_i32 +#define tcg_gen_ori_tl tcg_gen_ori_i32 +#define tcg_gen_xor_tl tcg_gen_xor_i32 +#define tcg_gen_xori_tl tcg_gen_xori_i32 +#define tcg_gen_not_tl tcg_gen_not_i32 +#define tcg_gen_shl_tl tcg_gen_shl_i32 +#define tcg_gen_shli_tl tcg_gen_shli_i32 +#define tcg_gen_shr_tl tcg_gen_shr_i32 +#define tcg_gen_shri_tl tcg_gen_shri_i32 +#define tcg_gen_sar_tl tcg_gen_sar_i32 +#define tcg_gen_sari_tl tcg_gen_sari_i32 +#define tcg_gen_brcond_tl tcg_gen_brcond_i32 +#define tcg_gen_brcondi_tl tcg_gen_brcondi_i32 +#define tcg_gen_mul_tl tcg_gen_mul_i32 +#define tcg_gen_muli_tl tcg_gen_muli_i32 +#define tcg_gen_div_tl tcg_gen_div_i32 +#define tcg_gen_rem_tl tcg_gen_rem_i32 +#define tcg_gen_divu_tl tcg_gen_divu_i32 +#define tcg_gen_remu_tl tcg_gen_remu_i32 +#define tcg_gen_discard_tl tcg_gen_discard_i32 +#define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32 +#define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32 +#define tcg_gen_extu_i32_tl tcg_gen_mov_i32 +#define tcg_gen_ext_i32_tl tcg_gen_mov_i32 +#define tcg_gen_extu_tl_i64 tcg_gen_extu_i32_i64 +#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64 +#define tcg_gen_ext8u_tl tcg_gen_ext8u_i32 +#define tcg_gen_ext8s_tl tcg_gen_ext8s_i32 +#define tcg_gen_ext16u_tl tcg_gen_ext16u_i32 +#define tcg_gen_ext16s_tl tcg_gen_ext16s_i32 +#define tcg_gen_ext32u_tl tcg_gen_mov_i32 +#define tcg_gen_ext32s_tl tcg_gen_mov_i32 +#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32 +#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32 +#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 +#define tcg_gen_andc_tl tcg_gen_andc_i32 +#define tcg_gen_eqv_tl tcg_gen_eqv_i32 +#define tcg_gen_nand_tl tcg_gen_nand_i32 +#define tcg_gen_nor_tl tcg_gen_nor_i32 +#define tcg_gen_orc_tl tcg_gen_orc_i32 +#define tcg_gen_rotl_tl tcg_gen_rotl_i32 +#define tcg_gen_rotli_tl tcg_gen_rotli_i32 +#define tcg_gen_rotr_tl tcg_gen_rotr_i32 +#define tcg_gen_rotri_tl tcg_gen_rotri_i32 +#define tcg_const_tl tcg_const_i32 +#define tcg_const_local_tl tcg_const_local_i32 +#endif + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_gen_add_ptr tcg_gen_add_i32 +#define tcg_gen_addi_ptr tcg_gen_addi_i32 +#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32 +#else /* TCG_TARGET_REG_BITS == 32 */ +#define tcg_gen_add_ptr tcg_gen_add_i64 +#define tcg_gen_addi_ptr tcg_gen_addi_i64 +#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64 +#endif /* TCG_TARGET_REG_BITS != 32 */ diff --git a/qemu/qemu-git/tcg/tcg-opc.h b/qemu/qemu-git/tcg/tcg-opc.h new file mode 100644 index 0000000..b7f3fd7 --- /dev/null +++ b/qemu/qemu-git/tcg/tcg-opc.h @@ -0,0 +1,272 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef DEF2 +#define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0) +#endif + +/* predefined ops */ +DEF2(end, 0, 0, 0, 0) /* must be kept first */ +DEF2(nop, 0, 0, 0, 0) +DEF2(nop1, 0, 0, 1, 0) +DEF2(nop2, 0, 0, 2, 0) +DEF2(nop3, 0, 0, 3, 0) +DEF2(nopn, 0, 0, 1, 0) /* variable number of parameters */ + +DEF2(discard, 1, 0, 0, 0) + +DEF2(set_label, 0, 0, 1, 0) +DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ +DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + +DEF2(mov_i32, 1, 1, 0, 0) +DEF2(movi_i32, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i32, 1, 1, 1, 0) +DEF2(ld8s_i32, 1, 1, 1, 0) +DEF2(ld16u_i32, 1, 1, 1, 0) +DEF2(ld16s_i32, 1, 1, 1, 0) +DEF2(ld_i32, 1, 1, 1, 0) +DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i32, 1, 2, 0, 0) +DEF2(sub_i32, 1, 2, 0, 0) +DEF2(mul_i32, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i32 +DEF2(div_i32, 1, 2, 0, 0) +DEF2(divu_i32, 1, 2, 0, 0) +DEF2(rem_i32, 1, 2, 0, 0) +DEF2(remu_i32, 1, 2, 0, 0) +#else +DEF2(div2_i32, 2, 3, 0, 0) +DEF2(divu2_i32, 2, 3, 0, 0) +#endif +DEF2(and_i32, 1, 2, 0, 0) +DEF2(or_i32, 1, 2, 0, 0) +DEF2(xor_i32, 1, 2, 0, 0) +/* shifts/rotates */ +DEF2(shl_i32, 1, 2, 0, 0) +DEF2(shr_i32, 1, 2, 0, 0) +DEF2(sar_i32, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_rot_i32 +DEF2(rotl_i32, 1, 2, 0, 0) +DEF2(rotr_i32, 1, 2, 0, 0) +#endif + +DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#if TCG_TARGET_REG_BITS == 32 +DEF2(add2_i32, 2, 4, 0, 0) +DEF2(sub2_i32, 2, 4, 0, 0) +DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(mulu2_i32, 2, 2, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8s_i32 +DEF2(ext8s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i32 +DEF2(ext16s_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8u_i32 +DEF2(ext8u_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16u_i32 +DEF2(ext16u_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap16_i32 +DEF2(bswap16_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap32_i32 +DEF2(bswap32_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_not_i32 +DEF2(not_i32, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_neg_i32 +DEF2(neg_i32, 1, 1, 0, 0) +#endif + +#if TCG_TARGET_REG_BITS == 64 +DEF2(mov_i64, 1, 1, 0, 0) +DEF2(movi_i64, 1, 0, 1, 0) +/* load/store */ +DEF2(ld8u_i64, 1, 1, 1, 0) +DEF2(ld8s_i64, 1, 1, 1, 0) +DEF2(ld16u_i64, 1, 1, 1, 0) +DEF2(ld16s_i64, 1, 1, 1, 0) +DEF2(ld32u_i64, 1, 1, 1, 0) +DEF2(ld32s_i64, 1, 1, 1, 0) +DEF2(ld_i64, 1, 1, 1, 0) +DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +/* arith */ +DEF2(add_i64, 1, 2, 0, 0) +DEF2(sub_i64, 1, 2, 0, 0) +DEF2(mul_i64, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_div_i64 +DEF2(div_i64, 1, 2, 0, 0) +DEF2(divu_i64, 1, 2, 0, 0) +DEF2(rem_i64, 1, 2, 0, 0) +DEF2(remu_i64, 1, 2, 0, 0) +#else +DEF2(div2_i64, 2, 3, 0, 0) +DEF2(divu2_i64, 2, 3, 0, 0) +#endif +DEF2(and_i64, 1, 2, 0, 0) +DEF2(or_i64, 1, 2, 0, 0) +DEF2(xor_i64, 1, 2, 0, 0) +/* shifts/rotates */ +DEF2(shl_i64, 1, 2, 0, 0) +DEF2(shr_i64, 1, 2, 0, 0) +DEF2(sar_i64, 1, 2, 0, 0) +#ifdef TCG_TARGET_HAS_rot_i64 +DEF2(rotl_i64, 1, 2, 0, 0) +DEF2(rotr_i64, 1, 2, 0, 0) +#endif + +DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +#ifdef TCG_TARGET_HAS_ext8s_i64 +DEF2(ext8s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16s_i64 +DEF2(ext16s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext32s_i64 +DEF2(ext32s_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext8u_i64 +DEF2(ext8u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext16u_i64 +DEF2(ext16u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_ext32u_i64 +DEF2(ext32u_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap16_i64 +DEF2(bswap16_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap32_i64 +DEF2(bswap32_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_bswap64_i64 +DEF2(bswap64_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_not_i64 +DEF2(not_i64, 1, 1, 0, 0) +#endif +#ifdef TCG_TARGET_HAS_neg_i64 +DEF2(neg_i64, 1, 1, 0, 0) +#endif +#endif + +/* QEMU specific */ +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS +DEF2(debug_insn_start, 0, 0, 2, 0) +#else +DEF2(debug_insn_start, 0, 0, 1, 0) +#endif +DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op + constants must be defined */ +#if TCG_TARGET_REG_BITS == 32 +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif +#if TARGET_LONG_BITS == 32 +DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#else +DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +#endif + +#else /* TCG_TARGET_REG_BITS == 32 */ + +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) + +#endif /* TCG_TARGET_REG_BITS != 32 */ + +#undef DEF2 diff --git a/qemu/qemu-git/tcg/tcg-runtime.h b/qemu/qemu-git/tcg/tcg-runtime.h new file mode 100644 index 0000000..e750cc1 --- /dev/null +++ b/qemu/qemu-git/tcg/tcg-runtime.h @@ -0,0 +1,13 @@ +#ifndef TCG_RUNTIME_H +#define TCG_RUNTIME_H + +/* tcg-runtime.c */ +int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); +uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); +uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); + +#endif diff --git a/qemu/qemu-git/tcg/tcg.c b/qemu/qemu-git/tcg/tcg.c new file mode 100644 index 0000000..3c0e296 --- /dev/null +++ b/qemu/qemu-git/tcg/tcg.c @@ -0,0 +1,2085 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* define it to use liveness analysis (better code) */ +#define USE_LIVENESS_ANALYSIS + +#include "config.h" + +#ifndef CONFIG_DEBUG_TCG +/* define it to suppress various consistency checks (faster) */ +#define NDEBUG +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif +#ifdef _AIX +#include +#endif + +#include "qemu-common.h" +#include "cache-utils.h" +#include "host-utils.h" + +/* Note: the long term plan is to reduce the dependancies on the QEMU + CPU definitions. Currently they are used for qemu_ld/st + instructions */ +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec-all.h" + +#include "tcg-op.h" +#include "elf.h" + +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) +#error GUEST_BASE not supported on this host. +#endif + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend); + +static TCGOpDef tcg_op_defs[] = { +#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size }, +#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 }, +#include "tcg-opc.h" +#undef DEF +#undef DEF2 +}; + +static TCGRegSet tcg_target_available_regs[2]; +static TCGRegSet tcg_target_call_clobber_regs; + +/* XXX: move that inside the context */ +uint16_t *gen_opc_ptr; +TCGArg *gen_opparam_ptr; + +static inline void tcg_out8(TCGContext *s, uint8_t v) +{ + *s->code_ptr++ = v; +} + +static inline void tcg_out16(TCGContext *s, uint16_t v) +{ + *(uint16_t *)s->code_ptr = v; + s->code_ptr += 2; +} + +static inline void tcg_out32(TCGContext *s, uint32_t v) +{ + *(uint32_t *)s->code_ptr = v; + s->code_ptr += 4; +} + +/* label relocation processing */ + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) { + /* FIXME: This may break relocations on RISC targets that + modify instruction fields in place. The caller may not have + written the initial value. */ + patch_reloc(code_ptr, type, l->u.value, addend); + } else { + /* add a new relocation entry */ + r = tcg_malloc(sizeof(TCGRelocation)); + r->type = type; + r->ptr = code_ptr; + r->addend = addend; + r->next = l->u.first_reloc; + l->u.first_reloc = r; + } +} + +static void tcg_out_label(TCGContext *s, int label_index, + tcg_target_long value) +{ + TCGLabel *l; + TCGRelocation *r; + + l = &s->labels[label_index]; + if (l->has_value) + tcg_abort(); + r = l->u.first_reloc; + while (r != NULL) { + patch_reloc(r->ptr, r->type, value, r->addend); + r = r->next; + } + l->has_value = 1; + l->u.value = value; +} + +int gen_new_label(void) +{ + TCGContext *s = &tcg_ctx; + int idx; + TCGLabel *l; + + if (s->nb_labels >= TCG_MAX_LABELS) + tcg_abort(); + idx = s->nb_labels++; + l = &s->labels[idx]; + l->has_value = 0; + l->u.first_reloc = NULL; + return idx; +} + +#include "tcg-target.c" + +/* pool based memory allocation */ +void *tcg_malloc_internal(TCGContext *s, int size) +{ + TCGPool *p; + int pool_size; + + if (size > TCG_POOL_CHUNK_SIZE) { + /* big malloc: insert a new pool (XXX: could optimize) */ + p = qemu_malloc(sizeof(TCGPool) + size); + p->size = size; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + p->next = s->pool_current; + } else { + p = s->pool_current; + if (!p) { + p = s->pool_first; + if (!p) + goto new_pool; + } else { + if (!p->next) { + new_pool: + pool_size = TCG_POOL_CHUNK_SIZE; + p = qemu_malloc(sizeof(TCGPool) + pool_size); + p->size = pool_size; + p->next = NULL; + if (s->pool_current) + s->pool_current->next = p; + else + s->pool_first = p; + } else { + p = p->next; + } + } + } + s->pool_current = p; + s->pool_cur = p->data + size; + s->pool_end = p->data + p->size; + return p->data; +} + +void tcg_pool_reset(TCGContext *s) +{ + s->pool_cur = s->pool_end = NULL; + s->pool_current = NULL; +} + +void tcg_context_init(TCGContext *s) +{ + int op, total_args, n; + TCGOpDef *def; + TCGArgConstraint *args_ct; + int *sorted_args; + + memset(s, 0, sizeof(*s)); + s->temps = s->static_temps; + s->nb_globals = 0; + + /* Count total number of arguments and allocate the corresponding + space */ + total_args = 0; + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + n = def->nb_iargs + def->nb_oargs; + total_args += n; + } + + args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args); + sorted_args = qemu_malloc(sizeof(int) * total_args); + + for(op = 0; op < NB_OPS; op++) { + def = &tcg_op_defs[op]; + def->args_ct = args_ct; + def->sorted_args = sorted_args; + n = def->nb_iargs + def->nb_oargs; + sorted_args += n; + args_ct += n; + } + + tcg_target_init(s); + + /* init global prologue and epilogue */ + s->code_buf = code_gen_prologue; + s->code_ptr = s->code_buf; + tcg_target_qemu_prologue(s); + flush_icache_range((unsigned long)s->code_buf, + (unsigned long)s->code_ptr); +} + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size) +{ + s->frame_start = start; + s->frame_end = start + size; + s->frame_reg = reg; +} + +void tcg_func_start(TCGContext *s) +{ + int i; + tcg_pool_reset(s); + s->nb_temps = s->nb_globals; + for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) + s->first_free_temp[i] = -1; + s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); + s->nb_labels = 0; + s->current_frame_offset = s->frame_start; + + gen_opc_ptr = gen_opc_buf; + gen_opparam_ptr = gen_opparam_buf; +} + +static inline void tcg_temp_alloc(TCGContext *s, int n) +{ + if (n > TCG_MAX_TEMPS) + tcg_abort(); +} + +static inline int tcg_global_reg_new_internal(TCGType type, int reg, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + +#if TCG_TARGET_REG_BITS == 32 + if (type != TCG_TYPE_I32) + tcg_abort(); +#endif + if (tcg_regset_test_reg(s->reserved_regs, reg)) + tcg_abort(); + idx = s->nb_globals; + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 1; + ts->reg = reg; + ts->name = name; + s->nb_globals++; + tcg_regset_set_reg(s->reserved_regs, reg); + return idx; +} + +TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name) +{ + int idx; + + idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name) +{ + int idx; + + idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name); + return MAKE_TCGV_I64(idx); +} + +static inline int tcg_global_mem_new_internal(TCGType type, int reg, + tcg_target_long offset, + const char *name) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx; + + idx = s->nb_globals; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + char buf[64]; + tcg_temp_alloc(s, s->nb_globals + 2); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset + 4; +#else + ts->mem_offset = offset; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_0"); + ts->name = strdup(buf); + ts++; + + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; +#ifdef TCG_TARGET_WORDS_BIGENDIAN + ts->mem_offset = offset; +#else + ts->mem_offset = offset + 4; +#endif + pstrcpy(buf, sizeof(buf), name); + pstrcat(buf, sizeof(buf), "_1"); + ts->name = strdup(buf); + + s->nb_globals += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_globals + 1); + ts = &s->temps[s->nb_globals]; + ts->base_type = type; + ts->type = type; + ts->fixed_reg = 0; + ts->mem_allocated = 1; + ts->mem_reg = reg; + ts->mem_offset = offset; + ts->name = name; + s->nb_globals++; + } + return idx; +} + +TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name); + return MAKE_TCGV_I64(idx); +} + +static inline int tcg_temp_new_internal(TCGType type, int temp_local) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int idx, k; + + k = type; + if (temp_local) + k += TCG_TYPE_COUNT; + idx = s->first_free_temp[k]; + if (idx != -1) { + /* There is already an available temp with the + right type */ + ts = &s->temps[idx]; + s->first_free_temp[k] = ts->next_free_temp; + ts->temp_allocated = 1; + assert(ts->temp_local == temp_local); + } else { + idx = s->nb_temps; +#if TCG_TARGET_REG_BITS == 32 + if (type == TCG_TYPE_I64) { + tcg_temp_alloc(s, s->nb_temps + 2); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + ts++; + ts->base_type = TCG_TYPE_I32; + ts->type = TCG_TYPE_I32; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps += 2; + } else +#endif + { + tcg_temp_alloc(s, s->nb_temps + 1); + ts = &s->temps[s->nb_temps]; + ts->base_type = type; + ts->type = type; + ts->temp_allocated = 1; + ts->temp_local = temp_local; + ts->name = NULL; + s->nb_temps++; + } + } + return idx; +} + +TCGv_i32 tcg_temp_new_internal_i32(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); + return MAKE_TCGV_I32(idx); +} + +TCGv_i64 tcg_temp_new_internal_i64(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); + return MAKE_TCGV_I64(idx); +} + +static inline void tcg_temp_free_internal(int idx) +{ + TCGContext *s = &tcg_ctx; + TCGTemp *ts; + int k; + + assert(idx >= s->nb_globals && idx < s->nb_temps); + ts = &s->temps[idx]; + assert(ts->temp_allocated != 0); + ts->temp_allocated = 0; + k = ts->base_type; + if (ts->temp_local) + k += TCG_TYPE_COUNT; + ts->next_free_temp = s->first_free_temp[k]; + s->first_free_temp[k] = idx; +} + +void tcg_temp_free_i32(TCGv_i32 arg) +{ + tcg_temp_free_internal(GET_TCGV_I32(arg)); +} + +void tcg_temp_free_i64(TCGv_i64 arg) +{ + tcg_temp_free_internal(GET_TCGV_I64(arg)); +} + +TCGv_i32 tcg_const_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv_i64 tcg_const_i64(int64_t val) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, val); + return t0; +} + +TCGv_i32 tcg_const_local_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_local_new_i32(); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv_i64 tcg_const_local_i64(int64_t val) +{ + TCGv_i64 t0; + t0 = tcg_temp_local_new_i64(); + tcg_gen_movi_i64(t0, val); + return t0; +} + +void tcg_register_helper(void *func, const char *name) +{ + TCGContext *s = &tcg_ctx; + int n; + if ((s->nb_helpers + 1) > s->allocated_helpers) { + n = s->allocated_helpers; + if (n == 0) { + n = 4; + } else { + n *= 2; + } + s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); + s->allocated_helpers = n; + } + s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; + s->helpers[s->nb_helpers].name = name; + s->nb_helpers++; +} + +/* Note: we convert the 64 bit args to 32 bit and do some alignment + and endian swap. Maybe it would be better to do the alignment + and endian swap in tcg_reg_alloc_call(). */ +void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, + int sizemask, TCGArg ret, int nargs, TCGArg *args) +{ + int call_type; + int i; + int real_args; + int nb_rets; + TCGArg *nparam; + *gen_opc_ptr++ = INDEX_op_call; + nparam = gen_opparam_ptr++; + call_type = (flags & TCG_CALL_TYPE_MASK); + if (ret != TCG_CALL_DUMMY_ARG) { +#if TCG_TARGET_REG_BITS < 64 + if (sizemask & 1) { +#ifdef TCG_TARGET_WORDS_BIGENDIAN + *gen_opparam_ptr++ = ret + 1; + *gen_opparam_ptr++ = ret; +#else + *gen_opparam_ptr++ = ret; + *gen_opparam_ptr++ = ret + 1; +#endif + nb_rets = 2; + } else +#endif + { + *gen_opparam_ptr++ = ret; + nb_rets = 1; + } + } else { + nb_rets = 0; + } + real_args = 0; + for (i = 0; i < nargs; i++) { +#if TCG_TARGET_REG_BITS < 64 + if (sizemask & (2 << i)) { +#ifdef TCG_TARGET_I386 + /* REGPARM case: if the third parameter is 64 bit, it is + allocated on the stack */ + if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { + call_type = TCG_CALL_TYPE_REGPARM_2; + flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; + } +#endif +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + /* some targets want aligned 64 bit args */ + if (real_args & 1) { + *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; + real_args++; + } +#endif +#ifdef TCG_TARGET_WORDS_BIGENDIAN + *gen_opparam_ptr++ = args[i] + 1; + *gen_opparam_ptr++ = args[i]; +#else + *gen_opparam_ptr++ = args[i]; + *gen_opparam_ptr++ = args[i] + 1; +#endif + real_args += 2; + } else +#endif + { + *gen_opparam_ptr++ = args[i]; + real_args++; + } + } + *gen_opparam_ptr++ = GET_TCGV_PTR(func); + + *gen_opparam_ptr++ = flags; + + *nparam = (nb_rets << 16) | (real_args + 1); + + /* total parameters, needed to go backward in the instruction stream */ + *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; +} + +#if TCG_TARGET_REG_BITS == 32 +void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, + int c, int right, int arith) +{ + if (c == 0) { + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); + } else if (c >= 32) { + c -= 32; + if (right) { + if (arith) { + tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); + tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); + } else { + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + } + } else { + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); + tcg_gen_movi_i32(TCGV_LOW(ret), 0); + } + } else { + TCGv_i32 t0, t1; + + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); + if (right) { + tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); + if (arith) + tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); + else + tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); + tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0); + tcg_gen_mov_i32(TCGV_HIGH(ret), t1); + } else { + tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); + /* Note: ret can be the same as arg1, so we use t1 */ + tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c); + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); + tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); + tcg_gen_mov_i32(TCGV_LOW(ret), t1); + } + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + } +} +#endif + +static void tcg_reg_alloc_start(TCGContext *s) +{ + int i; + TCGTemp *ts; + for(i = 0; i < s->nb_globals; i++) { + ts = &s->temps[i]; + if (ts->fixed_reg) { + ts->val_type = TEMP_VAL_REG; + } else { + ts->val_type = TEMP_VAL_MEM; + } + } + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + ts->val_type = TEMP_VAL_DEAD; + ts->mem_allocated = 0; + ts->fixed_reg = 0; + } + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + s->reg_to_temp[i] = -1; + } +} + +static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, + int idx) +{ + TCGTemp *ts; + + ts = &s->temps[idx]; + if (idx < s->nb_globals) { + pstrcpy(buf, buf_size, ts->name); + } else { + if (ts->temp_local) + snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); + else + snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); + } + return buf; +} + +char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg)); +} + +char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg)); +} + +static int helper_cmp(const void *p1, const void *p2) +{ + const TCGHelperInfo *th1 = p1; + const TCGHelperInfo *th2 = p2; + if (th1->func < th2->func) + return -1; + else if (th1->func == th2->func) + return 0; + else + return 1; +} + +/* find helper definition (Note: A hash table would be better) */ +static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) +{ + int m, m_min, m_max; + TCGHelperInfo *th; + tcg_target_ulong v; + + if (unlikely(!s->helpers_sorted)) { + qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), + helper_cmp); + s->helpers_sorted = 1; + } + + /* binary search */ + m_min = 0; + m_max = s->nb_helpers - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + th = &s->helpers[m]; + v = th->func; + if (v == val) + return th; + else if (val < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return NULL; +} + +static const char * const cond_name[] = +{ + [TCG_COND_EQ] = "eq", + [TCG_COND_NE] = "ne", + [TCG_COND_LT] = "lt", + [TCG_COND_GE] = "ge", + [TCG_COND_LE] = "le", + [TCG_COND_GT] = "gt", + [TCG_COND_LTU] = "ltu", + [TCG_COND_GEU] = "geu", + [TCG_COND_LEU] = "leu", + [TCG_COND_GTU] = "gtu" +}; + +void tcg_dump_ops(TCGContext *s, FILE *outfile) +{ + const uint16_t *opc_ptr; + const TCGArg *args; + TCGArg arg; + int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; + const TCGOpDef *def; + char buf[128]; + + first_insn = 1; + opc_ptr = gen_opc_buf; + args = gen_opparam_buf; + while (opc_ptr < gen_opc_ptr) { + c = *opc_ptr++; + def = &tcg_op_defs[c]; + if (c == INDEX_op_debug_insn_start) { + uint64_t pc; +#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS + pc = ((uint64_t)args[1] << 32) | args[0]; +#else + pc = args[0]; +#endif + if (!first_insn) + fprintf(outfile, "\n"); + fprintf(outfile, " ---- 0x%" PRIx64, pc); + first_insn = 0; + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } else if (c == INDEX_op_call) { + TCGArg arg; + + /* variable number of arguments */ + arg = *args++; + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_cargs = def->nb_cargs; + + fprintf(outfile, " %s ", def->name); + + /* function name */ + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); + /* flags */ + fprintf(outfile, ",$0x%" TCG_PRIlx, + args[nb_oargs + nb_iargs]); + /* nb out args */ + fprintf(outfile, ",$%d", nb_oargs); + for(i = 0; i < nb_oargs; i++) { + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); + } + for(i = 0; i < (nb_iargs - 1); i++) { + fprintf(outfile, ","); + if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { + fprintf(outfile, ""); + } else { + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); + } + } + } else if (c == INDEX_op_movi_i32 +#if TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_movi_i64 +#endif + ) { + tcg_target_ulong val; + TCGHelperInfo *th; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + fprintf(outfile, " %s %s,$", def->name, + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); + val = args[1]; + th = tcg_find_helper(s, val); + if (th) { + fprintf(outfile, "%s", th->name); + } else { + if (c == INDEX_op_movi_i32) + fprintf(outfile, "0x%x", (uint32_t)val); + else + fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); + } + } else { + fprintf(outfile, " %s ", def->name); + if (c == INDEX_op_nopn) { + /* variable number of arguments */ + nb_cargs = *args; + nb_oargs = 0; + nb_iargs = 0; + } else { + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_cargs = def->nb_cargs; + } + + k = 0; + for(i = 0; i < nb_oargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + for(i = 0; i < nb_iargs; i++) { + if (k != 0) + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + } + if (c == INDEX_op_brcond_i32 +#if TCG_TARGET_REG_BITS == 32 + || c == INDEX_op_brcond2_i32 +#elif TCG_TARGET_REG_BITS == 64 + || c == INDEX_op_brcond_i64 +#endif + ) { + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) + fprintf(outfile, ",%s", cond_name[args[k++]]); + else + fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); + i = 1; + } + else + i = 0; + for(; i < nb_cargs; i++) { + if (k != 0) + fprintf(outfile, ","); + arg = args[k++]; + fprintf(outfile, "$0x%" TCG_PRIlx, arg); + } + } + fprintf(outfile, "\n"); + args += nb_iargs + nb_oargs + nb_cargs; + } +} + +/* we give more priority to constraints with less registers */ +static int get_constraint_priority(const TCGOpDef *def, int k) +{ + const TCGArgConstraint *arg_ct; + + int i, n; + arg_ct = &def->args_ct[k]; + if (arg_ct->ct & TCG_CT_ALIAS) { + /* an alias is equivalent to a single register */ + n = 1; + } else { + if (!(arg_ct->ct & TCG_CT_REG)) + return 0; + n = 0; + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (tcg_regset_test_reg(arg_ct->u.regs, i)) + n++; + } + } + return TCG_TARGET_NB_REGS - n + 1; +} + +/* sort from highest priority to lowest */ +static void sort_constraints(TCGOpDef *def, int start, int n) +{ + int i, j, p1, p2, tmp; + + for(i = 0; i < n; i++) + def->sorted_args[start + i] = start + i; + if (n <= 1) + return; + for(i = 0; i < n - 1; i++) { + for(j = i + 1; j < n; j++) { + p1 = get_constraint_priority(def, def->sorted_args[start + i]); + p2 = get_constraint_priority(def, def->sorted_args[start + j]); + if (p1 < p2) { + tmp = def->sorted_args[start + i]; + def->sorted_args[start + i] = def->sorted_args[start + j]; + def->sorted_args[start + j] = tmp; + } + } + } +} + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) +{ + int op; + TCGOpDef *def; + const char *ct_str; + int i, nb_args; + + for(;;) { + if (tdefs->op < 0) + break; + op = tdefs->op; + assert(op >= 0 && op < NB_OPS); + def = &tcg_op_defs[op]; + nb_args = def->nb_iargs + def->nb_oargs; + for(i = 0; i < nb_args; i++) { + ct_str = tdefs->args_ct_str[i]; + tcg_regset_clear(def->args_ct[i].u.regs); + def->args_ct[i].ct = 0; + if (ct_str[0] >= '0' && ct_str[0] <= '9') { + int oarg; + oarg = ct_str[0] - '0'; + assert(oarg < def->nb_oargs); + assert(def->args_ct[oarg].ct & TCG_CT_REG); + /* TCG_CT_ALIAS is for the output arguments. The input + argument is tagged with TCG_CT_IALIAS. */ + def->args_ct[i] = def->args_ct[oarg]; + def->args_ct[oarg].ct = TCG_CT_ALIAS; + def->args_ct[oarg].alias_index = i; + def->args_ct[i].ct |= TCG_CT_IALIAS; + def->args_ct[i].alias_index = oarg; + } else { + for(;;) { + if (*ct_str == '\0') + break; + switch(*ct_str) { + case 'i': + def->args_ct[i].ct |= TCG_CT_CONST; + ct_str++; + break; + default: + if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { + fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", + ct_str, i, def->name); + exit(1); + } + } + } + } + } + + /* sort the constraints (XXX: this is just an heuristic) */ + sort_constraints(def, 0, def->nb_oargs); + sort_constraints(def, def->nb_oargs, def->nb_iargs); + +#if 0 + { + int i; + + printf("%s: sorted=", def->name); + for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) + printf(" %d", def->sorted_args[i]); + printf("\n"); + } +#endif + tdefs++; + } + +} + +#ifdef USE_LIVENESS_ANALYSIS + +/* set a nop for an operation using 'nb_args' */ +static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, + TCGArg *args, int nb_args) +{ + if (nb_args == 0) { + *opc_ptr = INDEX_op_nop; + } else { + *opc_ptr = INDEX_op_nopn; + args[0] = nb_args; + args[nb_args - 1] = nb_args; + } +} + +/* liveness analysis: end of function: globals are live, temps are + dead. */ +/* XXX: at this stage, not used as there would be little gains because + most TBs end with a conditional jump. */ +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) +{ + memset(dead_temps, 0, s->nb_globals); + memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); +} + +/* liveness analysis: end of basic block: globals are live, temps are + dead, local temps are live. */ +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) +{ + int i; + TCGTemp *ts; + + memset(dead_temps, 0, s->nb_globals); + ts = &s->temps[s->nb_globals]; + for(i = s->nb_globals; i < s->nb_temps; i++) { + if (ts->temp_local) + dead_temps[i] = 0; + else + dead_temps[i] = 1; + ts++; + } +} + +/* Liveness analysis : update the opc_dead_iargs array to tell if a + given input arguments is dead. Instructions updating dead + temporaries are removed. */ +static void tcg_liveness_analysis(TCGContext *s) +{ + int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + TCGArg *args; + const TCGOpDef *def; + uint8_t *dead_temps; + unsigned int dead_iargs; + + gen_opc_ptr++; /* skip end */ + + nb_ops = gen_opc_ptr - gen_opc_buf; + + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); + + dead_temps = tcg_malloc(s->nb_temps); + memset(dead_temps, 1, s->nb_temps); + + args = gen_opparam_ptr; + op_index = nb_ops - 1; + while (op_index >= 0) { + op = gen_opc_buf[op_index]; + def = &tcg_op_defs[op]; + switch(op) { + case INDEX_op_call: + { + int call_flags; + + nb_args = args[-1]; + args -= nb_args; + nb_iargs = args[0] & 0xffff; + nb_oargs = args[0] >> 16; + args++; + call_flags = args[nb_oargs + nb_iargs]; + + /* pure functions can be removed if their result is not + used */ + if (call_flags & TCG_CALL_PURE) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove_call; + } + tcg_set_nop(s, gen_opc_buf + op_index, + args - 1, nb_args); + } else { + do_not_remove_call: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + if (!(call_flags & TCG_CALL_CONST)) { + /* globals are live (they may be used by the call) */ + memset(dead_temps, 0, s->nb_globals); + } + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (arg != TCG_CALL_DUMMY_ARG) { + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + } + s->op_dead_iargs[op_index] = dead_iargs; + } + args--; + } + break; + case INDEX_op_set_label: + args--; + /* mark end of basic block */ + tcg_la_bb_end(s, dead_temps); + break; + case INDEX_op_debug_insn_start: + args -= def->nb_args; + break; + case INDEX_op_nopn: + nb_args = args[-1]; + args -= nb_args; + break; + case INDEX_op_discard: + args--; + /* mark the temporary as dead */ + dead_temps[args[0]] = 1; + break; + case INDEX_op_end: + break; + /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ + default: + args -= def->nb_args; + nb_iargs = def->nb_iargs; + nb_oargs = def->nb_oargs; + + /* Test if the operation can be removed because all + its outputs are dead. We assume that nb_oargs == 0 + implies side effects */ + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove; + } + tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); +#ifdef CONFIG_PROFILER + s->del_op_count++; +#endif + } else { + do_not_remove: + + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } + + /* if end of basic block, update */ + if (def->flags & TCG_OPF_BB_END) { + tcg_la_bb_end(s, dead_temps); + } else if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* globals are live */ + memset(dead_temps, 0, s->nb_globals); + } + + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (dead_temps[arg]) { + dead_iargs |= (1 << i); + } + dead_temps[arg] = 0; + } + s->op_dead_iargs[op_index] = dead_iargs; + } + break; + } + op_index--; + } + + if (args != gen_opparam_buf) + tcg_abort(); +} +#else +/* dummy liveness analysis */ +void tcg_liveness_analysis(TCGContext *s) +{ + int nb_ops; + nb_ops = gen_opc_ptr - gen_opc_buf; + + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); + memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t)); +} +#endif + +#ifndef NDEBUG +static void dump_regs(TCGContext *s) +{ + TCGTemp *ts; + int i; + char buf[64]; + + for(i = 0; i < s->nb_temps; i++) { + ts = &s->temps[i]; + printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); + switch(ts->val_type) { + case TEMP_VAL_REG: + printf("%s", tcg_target_reg_names[ts->reg]); + break; + case TEMP_VAL_MEM: + printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); + break; + case TEMP_VAL_CONST: + printf("$0x%" TCG_PRIlx, ts->val); + break; + case TEMP_VAL_DEAD: + printf("D"); + break; + default: + printf("???"); + break; + } + printf("\n"); + } + + for(i = 0; i < TCG_TARGET_NB_REGS; i++) { + if (s->reg_to_temp[i] >= 0) { + printf("%s: %s\n", + tcg_target_reg_names[i], + tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); + } + } +} + +static void check_regs(TCGContext *s) +{ + int reg, k; + TCGTemp *ts; + char buf[64]; + + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + k = s->reg_to_temp[reg]; + if (k >= 0) { + ts = &s->temps[k]; + if (ts->val_type != TEMP_VAL_REG || + ts->reg != reg) { + printf("Inconsistency for register %s:\n", + tcg_target_reg_names[reg]); + goto fail; + } + } + } + for(k = 0; k < s->nb_temps; k++) { + ts = &s->temps[k]; + if (ts->val_type == TEMP_VAL_REG && + !ts->fixed_reg && + s->reg_to_temp[ts->reg] != k) { + printf("Inconsistency for temp %s:\n", + tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); + fail: + printf("reg state:\n"); + dump_regs(s); + tcg_abort(); + } + } +} +#endif + +static void temp_allocate_frame(TCGContext *s, int temp) +{ + TCGTemp *ts; + ts = &s->temps[temp]; + s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); + if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) + tcg_abort(); + ts->mem_offset = s->current_frame_offset; + ts->mem_reg = s->frame_reg; + ts->mem_allocated = 1; + s->current_frame_offset += sizeof(tcg_target_long); +} + +/* free register 'reg' by spilling the corresponding temporary if necessary */ +static void tcg_reg_free(TCGContext *s, int reg) +{ + TCGTemp *ts; + int temp; + + temp = s->reg_to_temp[reg]; + if (temp != -1) { + ts = &s->temps[temp]; + assert(ts->val_type == TEMP_VAL_REG); + if (!ts->mem_coherent) { + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } + ts->val_type = TEMP_VAL_MEM; + s->reg_to_temp[reg] = -1; + } +} + +/* Allocate a register belonging to reg1 & ~reg2 */ +static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) +{ + int i, reg; + TCGRegSet reg_ct; + + tcg_regset_andnot(reg_ct, reg1, reg2); + + /* first try free registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) + return reg; + } + + /* XXX: do better spill choice */ + for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { + reg = tcg_target_reg_alloc_order[i]; + if (tcg_regset_test_reg(reg_ct, reg)) { + tcg_reg_free(s, reg); + return reg; + } + } + + tcg_abort(); +} + +/* save a temporary to memory. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int reg; + + ts = &s->temps[temp]; + if (!ts->fixed_reg) { + switch(ts->val_type) { + case TEMP_VAL_REG: + tcg_reg_free(s, ts->reg); + break; + case TEMP_VAL_DEAD: + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_CONST: + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + allocated_regs); + if (!ts->mem_allocated) + temp_allocate_frame(s, temp); + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_MEM; + break; + case TEMP_VAL_MEM: + break; + default: + tcg_abort(); + } + } +} + +/* save globals to their cannonical location and assume they can be + modified be the following code. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void save_globals(TCGContext *s, TCGRegSet allocated_regs) +{ + int i; + + for(i = 0; i < s->nb_globals; i++) { + temp_save(s, i, allocated_regs); + } +} + +/* at the end of a basic block, we assume all temporaries are dead and + all globals are stored at their canonical location. */ +static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) +{ + TCGTemp *ts; + int i; + + for(i = s->nb_globals; i < s->nb_temps; i++) { + ts = &s->temps[i]; + if (ts->temp_local) { + temp_save(s, i, allocated_regs); + } else { + if (ts->val_type == TEMP_VAL_REG) { + s->reg_to_temp[ts->reg] = -1; + } + ts->val_type = TEMP_VAL_DEAD; + } + } + + save_globals(s, allocated_regs); +} + +#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) + +static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) +{ + TCGTemp *ots; + tcg_target_ulong val; + + ots = &s->temps[args[0]]; + val = args[1]; + + if (ots->fixed_reg) { + /* for fixed registers, we do not do any constant + propagation */ + tcg_out_movi(s, ots->type, ots->reg, val); + } else { + /* The movi is not explicitly generated here */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = val; + } +} + +static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGTemp *ts, *ots; + int reg; + const TCGArgConstraint *arg_ct; + + ots = &s->temps[args[0]]; + ts = &s->temps[args[1]]; + arg_ct = &def->args_ct[0]; + + /* XXX: always mark arg dead if IS_DEAD_IARG(0) */ + if (ts->val_type == TEMP_VAL_REG) { + if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { + /* the mov can be suppressed */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + reg = ts->reg; + s->reg_to_temp[reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } else { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } + } else if (ts->val_type == TEMP_VAL_MEM) { + if (ots->val_type == TEMP_VAL_REG) { + reg = ots->reg; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + } + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (ots->fixed_reg) { + reg = ots->reg; + tcg_out_movi(s, ots->type, reg, ts->val); + } else { + /* propagate constant */ + if (ots->val_type == TEMP_VAL_REG) + s->reg_to_temp[ots->reg] = -1; + ots->val_type = TEMP_VAL_CONST; + ots->val = ts->val; + return; + } + } else { + tcg_abort(); + } + s->reg_to_temp[reg] = args[0]; + ots->reg = reg; + ots->val_type = TEMP_VAL_REG; + ots->mem_coherent = 0; +} + +static void tcg_reg_alloc_op(TCGContext *s, + const TCGOpDef *def, int opc, + const TCGArg *args, + unsigned int dead_iargs) +{ + TCGRegSet allocated_regs; + int i, k, nb_iargs, nb_oargs, reg; + TCGArg arg; + const TCGArgConstraint *arg_ct; + TCGTemp *ts; + TCGArg new_args[TCG_MAX_OP_ARGS]; + int const_args[TCG_MAX_OP_ARGS]; + + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + + /* copy constants */ + memcpy(new_args + nb_oargs + nb_iargs, + args + nb_oargs + nb_iargs, + sizeof(TCGArg) * def->nb_cargs); + + /* satisfy input constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_iargs; k++) { + i = def->sorted_args[nb_oargs + k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 1; + s->reg_to_temp[reg] = arg; + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(ts->val, arg_ct)) { + /* constant is OK for instruction */ + const_args[i] = 1; + new_args[i] = ts->val; + goto iarg_end; + } else { + /* need to move to a register */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, ts->val); + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + assert(ts->val_type == TEMP_VAL_REG); + if (arg_ct->ct & TCG_CT_IALIAS) { + if (ts->fixed_reg) { + /* if fixed register, we must allocate a new register + if the alias is not the same register */ + if (arg != args[arg_ct->alias_index]) + goto allocate_in_reg; + } else { + /* if the input is aliased to an output and if it is + not dead after the instruction, we must allocate + a new register and move it */ + if (!IS_DEAD_IARG(i - nb_oargs)) + goto allocate_in_reg; + } + } + reg = ts->reg; + if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { + /* nothing to do : the constraint is satisfied */ + } else { + allocate_in_reg: + /* allocate a new register matching the constraint + and move the temporary register into it */ + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + new_args[i] = reg; + const_args[i] = 0; + tcg_regset_set_reg(allocated_regs, reg); + iarg_end: ; + } + + if (def->flags & TCG_OPF_BB_END) { + tcg_reg_alloc_bb_end(s, allocated_regs); + } else { + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* XXX: permit generic clobber register list ? */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + /* XXX: for load/store we could do that only for the slow path + (i.e. when a memory callback is called) */ + + /* store globals and free associated registers (we assume the insn + can modify any global. */ + save_globals(s, allocated_regs); + } + + /* satisfy the output constraints */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(k = 0; k < nb_oargs; k++) { + i = def->sorted_args[k]; + arg = args[i]; + arg_ct = &def->args_ct[i]; + ts = &s->temps[arg]; + if (arg_ct->ct & TCG_CT_ALIAS) { + reg = new_args[arg_ct->alias_index]; + } else { + /* if fixed register, we try to use it */ + reg = ts->reg; + if (ts->fixed_reg && + tcg_regset_test_reg(arg_ct->u.regs, reg)) { + goto oarg_end; + } + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + } + tcg_regset_set_reg(allocated_regs, reg); + /* if a fixed register is used, then a move will be done afterwards */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + /* temp value is modified, so the value kept in memory is + potentially not the same */ + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + oarg_end: + new_args[i] = reg; + } + } + + /* emit instruction */ + tcg_out_op(s, opc, new_args, const_args); + + /* move the outputs in the correct register if needed */ + for(i = 0; i < nb_oargs; i++) { + ts = &s->temps[args[i]]; + reg = new_args[i]; + if (ts->fixed_reg && ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } +} + +#ifdef TCG_TARGET_STACK_GROWSUP +#define STACK_DIR(x) (-(x)) +#else +#define STACK_DIR(x) (x) +#endif + +static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, + int opc, const TCGArg *args, + unsigned int dead_iargs) +{ + int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; + TCGArg arg, func_arg; + TCGTemp *ts; + tcg_target_long stack_offset, call_stack_size, func_addr; + int const_func_arg, allocate_args; + TCGRegSet allocated_regs; + const TCGArgConstraint *arg_ct; + + arg = *args++; + + nb_oargs = arg >> 16; + nb_iargs = arg & 0xffff; + nb_params = nb_iargs - 1; + + flags = args[nb_oargs + nb_iargs]; + + nb_regs = tcg_target_get_call_iarg_regs_count(flags); + if (nb_regs > nb_params) + nb_regs = nb_params; + + /* assign stack slots first */ + /* XXX: preallocate call stack */ + call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); + call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); + } + + stack_offset = TCG_TARGET_CALL_STACK_OFFSET; + for(i = nb_regs; i < nb_params; i++) { + arg = args[nb_oargs + i]; +#ifdef TCG_TARGET_STACK_GROWSUP + stack_offset -= sizeof(tcg_target_long); +#endif + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + if (ts->val_type == TEMP_VAL_REG) { + tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: not correct if reading values from the stack */ + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + s->reserved_regs); + /* XXX: sign extend may be needed on some targets */ + tcg_out_movi(s, ts->type, reg, ts->val); + tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); + } else { + tcg_abort(); + } + } +#ifndef TCG_TARGET_STACK_GROWSUP + stack_offset += sizeof(tcg_target_long); +#endif + } + + /* assign input registers */ + tcg_regset_set(allocated_regs, s->reserved_regs); + for(i = 0; i < nb_regs; i++) { + arg = args[nb_oargs + i]; + if (arg != TCG_CALL_DUMMY_ARG) { + ts = &s->temps[arg]; + reg = tcg_target_call_iarg_regs[i]; + tcg_reg_free(s, reg); + if (ts->val_type == TEMP_VAL_REG) { + if (ts->reg != reg) { + tcg_out_mov(s, reg, ts->reg); + } + } else if (ts->val_type == TEMP_VAL_MEM) { + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + /* XXX: sign extend ? */ + tcg_out_movi(s, ts->type, reg, ts->val); + } else { + tcg_abort(); + } + tcg_regset_set_reg(allocated_regs, reg); + } + } + + /* assign function address */ + func_arg = args[nb_oargs + nb_iargs - 1]; + arg_ct = &def->args_ct[0]; + ts = &s->temps[func_arg]; + func_addr = ts->val; + const_func_arg = 0; + if (ts->val_type == TEMP_VAL_MEM) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_REG) { + reg = ts->reg; + if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_mov(s, reg, ts->reg); + } + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } else if (ts->val_type == TEMP_VAL_CONST) { + if (tcg_target_const_match(func_addr, arg_ct)) { + const_func_arg = 1; + func_arg = func_addr; + } else { + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + tcg_out_movi(s, ts->type, reg, func_addr); + func_arg = reg; + tcg_regset_set_reg(allocated_regs, reg); + } + } else { + tcg_abort(); + } + + + /* mark dead temporaries and free the associated registers */ + for(i = 0; i < nb_iargs; i++) { + arg = args[nb_oargs + i]; + if (IS_DEAD_IARG(i)) { + ts = &s->temps[arg]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + } + + /* clobber call registers */ + for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { + tcg_reg_free(s, reg); + } + } + + /* store globals and free associated registers (we assume the call + can modify any global. */ + if (!(flags & TCG_CALL_CONST)) { + save_globals(s, allocated_regs); + } + + tcg_out_op(s, opc, &func_arg, &const_func_arg); + + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); + } + + /* assign output registers and emit moves if needed */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + ts = &s->temps[arg]; + reg = tcg_target_call_oarg_regs[i]; + assert(s->reg_to_temp[reg] == -1); + if (ts->fixed_reg) { + if (ts->reg != reg) { + tcg_out_mov(s, ts->reg, reg); + } + } else { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + } + } + + return nb_iargs + nb_oargs + def->nb_cargs + 1; +} + +#ifdef CONFIG_PROFILER + +static int64_t tcg_table_op_count[NB_OPS]; + +static void dump_op_count(void) +{ + int i; + FILE *f; + f = fopen("/tmp/op.log", "w"); + for(i = INDEX_op_end; i < NB_OPS; i++) { + fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]); + } + fclose(f); +} +#endif + + +static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, + long search_pc) +{ + int opc, op_index; + const TCGOpDef *def; + unsigned int dead_iargs; + const TCGArg *args; + +#ifdef DEBUG_DISAS + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + qemu_log("OP:\n"); + tcg_dump_ops(s, logfile); + qemu_log("\n"); + } +#endif + +#ifdef CONFIG_PROFILER + s->la_time -= profile_getclock(); +#endif + tcg_liveness_analysis(s); +#ifdef CONFIG_PROFILER + s->la_time += profile_getclock(); +#endif + +#ifdef DEBUG_DISAS + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { + qemu_log("OP after liveness analysis:\n"); + tcg_dump_ops(s, logfile); + qemu_log("\n"); + } +#endif + + tcg_reg_alloc_start(s); + + s->code_buf = gen_code_buf; + s->code_ptr = gen_code_buf; + + args = gen_opparam_buf; + op_index = 0; + + for(;;) { + opc = gen_opc_buf[op_index]; +#ifdef CONFIG_PROFILER + tcg_table_op_count[opc]++; +#endif + def = &tcg_op_defs[opc]; +#if 0 + printf("%s: %d %d %d\n", def->name, + def->nb_oargs, def->nb_iargs, def->nb_cargs); + // dump_regs(s); +#endif + switch(opc) { + case INDEX_op_mov_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_mov_i64: +#endif + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_mov(s, def, args, dead_iargs); + break; + case INDEX_op_movi_i32: +#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: +#endif + tcg_reg_alloc_movi(s, args); + break; + case INDEX_op_debug_insn_start: + /* debug instruction */ + break; + case INDEX_op_nop: + case INDEX_op_nop1: + case INDEX_op_nop2: + case INDEX_op_nop3: + break; + case INDEX_op_nopn: + args += args[0]; + goto next; + case INDEX_op_discard: + { + TCGTemp *ts; + ts = &s->temps[args[0]]; + /* mark the temporary as dead */ + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + break; + case INDEX_op_set_label: + tcg_reg_alloc_bb_end(s, s->reserved_regs); + tcg_out_label(s, args[0], (long)s->code_ptr); + break; + case INDEX_op_call: + dead_iargs = s->op_dead_iargs[op_index]; + args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); + goto next; + case INDEX_op_end: + goto the_end; + default: + /* Note: in order to speed up the code, it would be much + faster to have specialized register allocator functions for + some common argument patterns */ + dead_iargs = s->op_dead_iargs[op_index]; + tcg_reg_alloc_op(s, def, opc, args, dead_iargs); + break; + } + args += def->nb_args; + next: + if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { + return op_index; + } + op_index++; +#ifndef NDEBUG + check_regs(s); +#endif + } + the_end: + return -1; +} + +int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) +{ +#ifdef CONFIG_PROFILER + { + int n; + n = (gen_opc_ptr - gen_opc_buf); + s->op_count += n; + if (n > s->op_count_max) + s->op_count_max = n; + + s->temp_count += s->nb_temps; + if (s->nb_temps > s->temp_count_max) + s->temp_count_max = s->nb_temps; + } +#endif + + tcg_gen_code_common(s, gen_code_buf, -1); + + /* flush instruction cache */ + flush_icache_range((unsigned long)gen_code_buf, + (unsigned long)s->code_ptr); + return s->code_ptr - gen_code_buf; +} + +/* Return the index of the micro operation such as the pc after is < + offset bytes from the start of the TB. The contents of gen_code_buf must + not be changed, though writing the same values is ok. + Return -1 if not found. */ +int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) +{ + return tcg_gen_code_common(s, gen_code_buf, offset); +} + +#ifdef CONFIG_PROFILER +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + TCGContext *s = &tcg_ctx; + int64_t tot; + + tot = s->interm_time + s->code_time; + cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", + tot, tot / 2.4e9); + cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", + s->tb_count, + s->tb_count1 - s->tb_count, + s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); + cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", + s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); + cpu_fprintf(f, "deleted ops/TB %0.2f\n", + s->tb_count ? + (double)s->del_op_count / s->tb_count : 0); + cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", + s->tb_count ? + (double)s->temp_count / s->tb_count : 0, + s->temp_count_max); + + cpu_fprintf(f, "cycles/op %0.1f\n", + s->op_count ? (double)tot / s->op_count : 0); + cpu_fprintf(f, "cycles/in byte %0.1f\n", + s->code_in_len ? (double)tot / s->code_in_len : 0); + cpu_fprintf(f, "cycles/out byte %0.1f\n", + s->code_out_len ? (double)tot / s->code_out_len : 0); + if (tot == 0) + tot = 1; + cpu_fprintf(f, " gen_interm time %0.1f%%\n", + (double)s->interm_time / tot * 100.0); + cpu_fprintf(f, " gen_code time %0.1f%%\n", + (double)s->code_time / tot * 100.0); + cpu_fprintf(f, "liveness/code time %0.1f%%\n", + (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); + cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", + s->restore_count); + cpu_fprintf(f, " avg cycles %0.1f\n", + s->restore_count ? (double)s->restore_time / s->restore_count : 0); + + dump_op_count(); +} +#else +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + cpu_fprintf(f, "[TCG profiler not compiled]\n"); +} +#endif diff --git a/qemu/qemu-git/tcg/tcg.h b/qemu/qemu-git/tcg/tcg.h new file mode 100644 index 0000000..121b17c --- /dev/null +++ b/qemu/qemu-git/tcg/tcg.h @@ -0,0 +1,468 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "tcg-target.h" +#include "tcg-runtime.h" + +#if TCG_TARGET_REG_BITS == 32 +typedef int32_t tcg_target_long; +typedef uint32_t tcg_target_ulong; +#define TCG_PRIlx PRIx32 +#define TCG_PRIld PRId32 +#elif TCG_TARGET_REG_BITS == 64 +typedef int64_t tcg_target_long; +typedef uint64_t tcg_target_ulong; +#define TCG_PRIlx PRIx64 +#define TCG_PRIld PRId64 +#else +#error unsupported +#endif + +#if TCG_TARGET_NB_REGS <= 32 +typedef uint32_t TCGRegSet; +#elif TCG_TARGET_NB_REGS <= 64 +typedef uint64_t TCGRegSet; +#else +#error unsupported +#endif + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "tcg-opc.h" +#undef DEF + NB_OPS, +}; + +#define tcg_regset_clear(d) (d) = 0 +#define tcg_regset_set(d, s) (d) = (s) +#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg) +#define tcg_regset_set_reg(d, r) (d) |= 1L << (r) +#define tcg_regset_reset_reg(d, r) (d) &= ~(1L << (r)) +#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1) +#define tcg_regset_or(d, a, b) (d) = (a) | (b) +#define tcg_regset_and(d, a, b) (d) = (a) & (b) +#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b) +#define tcg_regset_not(d, a) (d) = ~(a) + +typedef struct TCGRelocation { + struct TCGRelocation *next; + int type; + uint8_t *ptr; + tcg_target_long addend; +} TCGRelocation; + +typedef struct TCGLabel { + int has_value; + union { + tcg_target_ulong value; + TCGRelocation *first_reloc; + } u; +} TCGLabel; + +typedef struct TCGPool { + struct TCGPool *next; + int size; + uint8_t data[0] __attribute__ ((aligned)); +} TCGPool; + +#define TCG_POOL_CHUNK_SIZE 32768 + +#define TCG_MAX_LABELS 512 + +#define TCG_MAX_TEMPS 512 + +/* when the size of the arguments of a called function is smaller than + this value, they are statically allocated in the TB stack frame */ +#define TCG_STATIC_CALL_ARGS_SIZE 128 + +typedef int TCGType; + +#define TCG_TYPE_I32 0 +#define TCG_TYPE_I64 1 +#define TCG_TYPE_COUNT 2 /* number of different types */ + +#if TCG_TARGET_REG_BITS == 32 +#define TCG_TYPE_PTR TCG_TYPE_I32 +#else +#define TCG_TYPE_PTR TCG_TYPE_I64 +#endif + +typedef tcg_target_ulong TCGArg; + +/* Define a type and accessor macros for varables. Using a struct is + nice because it gives some level of type safely. Ideally the compiler + be able to see through all this. However in practice this is not true, + expecially on targets with braindamaged ABIs (e.g. i386). + We use plain int by default to avoid this runtime overhead. + Users of tcg_gen_* don't need to know about any of this, and should + treat TCGv as an opaque type. + In additon we do typechecking for different types of variables. TCGv_i32 + and TCGv_i64 are 32/64-bit variables respectively. TCGv and TCGv_ptr + are aliases for target_ulong and host pointer sized values respectively. + */ + +#ifdef CONFIG_DEBUG_TCG +#define DEBUG_TCGV 1 +#endif + +#ifdef DEBUG_TCGV + +typedef struct +{ + int i32; +} TCGv_i32; + +typedef struct +{ + int i64; +} TCGv_i64; + +#define MAKE_TCGV_I32(i) __extension__ \ + ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;}) +#define MAKE_TCGV_I64(i) __extension__ \ + ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;}) +#define GET_TCGV_I32(t) ((t).i32) +#define GET_TCGV_I64(t) ((t).i64) +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t)) +#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1) +#endif + +#else /* !DEBUG_TCGV */ + +typedef int TCGv_i32; +typedef int TCGv_i64; +#define MAKE_TCGV_I32(x) (x) +#define MAKE_TCGV_I64(x) (x) +#define GET_TCGV_I32(t) (t) +#define GET_TCGV_I64(t) (t) + +#if TCG_TARGET_REG_BITS == 32 +#define TCGV_LOW(t) (t) +#define TCGV_HIGH(t) ((t) + 1) +#endif + +#endif /* DEBUG_TCGV */ + +#define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b)) +#define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b)) + +/* Dummy definition to avoid compiler warnings. */ +#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1) +#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) + +/* call flags */ +#define TCG_CALL_TYPE_MASK 0x000f +#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */ +#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */ +#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */ +#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */ +/* A pure function only reads its arguments and TCG global variables + and cannot raise exceptions. Hence a call to a pure function can be + safely suppressed if the return value is not used. */ +#define TCG_CALL_PURE 0x0010 +/* A const function only reads its arguments and does not use TCG + global variables. Hence a call to such a function does not + save TCG global variables back to their canonical location. */ +#define TCG_CALL_CONST 0x0020 + +/* used to align parameters */ +#define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) +#define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) + +typedef enum { + TCG_COND_EQ, + TCG_COND_NE, + TCG_COND_LT, + TCG_COND_GE, + TCG_COND_LE, + TCG_COND_GT, + /* unsigned */ + TCG_COND_LTU, + TCG_COND_GEU, + TCG_COND_LEU, + TCG_COND_GTU, +} TCGCond; + +static inline TCGCond tcg_unsigned_cond(TCGCond c) +{ + return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c); +} + +#define TEMP_VAL_DEAD 0 +#define TEMP_VAL_REG 1 +#define TEMP_VAL_MEM 2 +#define TEMP_VAL_CONST 3 + +/* XXX: optimize memory layout */ +typedef struct TCGTemp { + TCGType base_type; + TCGType type; + int val_type; + int reg; + tcg_target_long val; + int mem_reg; + tcg_target_long mem_offset; + unsigned int fixed_reg:1; + unsigned int mem_coherent:1; + unsigned int mem_allocated:1; + unsigned int temp_local:1; /* If true, the temp is saved accross + basic blocks. Otherwise, it is not + preserved accross basic blocks. */ + unsigned int temp_allocated:1; /* never used for code gen */ + /* index of next free temp of same base type, -1 if end */ + int next_free_temp; + const char *name; +} TCGTemp; + +typedef struct TCGHelperInfo { + tcg_target_ulong func; + const char *name; +} TCGHelperInfo; + +typedef struct TCGContext TCGContext; + +struct TCGContext { + uint8_t *pool_cur, *pool_end; + TCGPool *pool_first, *pool_current; + TCGLabel *labels; + int nb_labels; + TCGTemp *temps; /* globals first, temps after */ + int nb_globals; + int nb_temps; + /* index of free temps, -1 if none */ + int first_free_temp[TCG_TYPE_COUNT * 2]; + + /* goto_tb support */ + uint8_t *code_buf; + unsigned long *tb_next; + uint16_t *tb_next_offset; + uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ + + /* liveness analysis */ + uint16_t *op_dead_iargs; /* for each operation, each bit tells if the + corresponding input argument is dead */ + + /* tells in which temporary a given register is. It does not take + into account fixed registers */ + int reg_to_temp[TCG_TARGET_NB_REGS]; + TCGRegSet reserved_regs; + tcg_target_long current_frame_offset; + tcg_target_long frame_start; + tcg_target_long frame_end; + int frame_reg; + + uint8_t *code_ptr; + TCGTemp static_temps[TCG_MAX_TEMPS]; + + TCGHelperInfo *helpers; + int nb_helpers; + int allocated_helpers; + int helpers_sorted; + +#ifdef CONFIG_PROFILER + /* profiling info */ + int64_t tb_count1; + int64_t tb_count; + int64_t op_count; /* total insn count */ + int op_count_max; /* max insn per TB */ + int64_t temp_count; + int temp_count_max; + int64_t del_op_count; + int64_t code_in_len; + int64_t code_out_len; + int64_t interm_time; + int64_t code_time; + int64_t la_time; + int64_t restore_count; + int64_t restore_time; +#endif +}; + +extern TCGContext tcg_ctx; +extern uint16_t *gen_opc_ptr; +extern TCGArg *gen_opparam_ptr; +extern uint16_t gen_opc_buf[]; +extern TCGArg gen_opparam_buf[]; + +/* pool based memory allocation */ + +void *tcg_malloc_internal(TCGContext *s, int size); +void tcg_pool_reset(TCGContext *s); +void tcg_pool_delete(TCGContext *s); + +static inline void *tcg_malloc(int size) +{ + TCGContext *s = &tcg_ctx; + uint8_t *ptr, *ptr_end; + size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1); + ptr = s->pool_cur; + ptr_end = ptr + size; + if (unlikely(ptr_end > s->pool_end)) { + return tcg_malloc_internal(&tcg_ctx, size); + } else { + s->pool_cur = ptr_end; + return ptr; + } +} + +void tcg_context_init(TCGContext *s); +void tcg_func_start(TCGContext *s); + +int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf); +int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset); + +void tcg_set_frame(TCGContext *s, int reg, + tcg_target_long start, tcg_target_long size); + +TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name); +TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, + const char *name); +TCGv_i32 tcg_temp_new_internal_i32(int temp_local); +static inline TCGv_i32 tcg_temp_new_i32(void) +{ + return tcg_temp_new_internal_i32(0); +} +static inline TCGv_i32 tcg_temp_local_new_i32(void) +{ + return tcg_temp_new_internal_i32(1); +} +void tcg_temp_free_i32(TCGv_i32 arg); +char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg); + +TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name); +TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, + const char *name); +TCGv_i64 tcg_temp_new_internal_i64(int temp_local); +static inline TCGv_i64 tcg_temp_new_i64(void) +{ + return tcg_temp_new_internal_i64(0); +} +static inline TCGv_i64 tcg_temp_local_new_i64(void) +{ + return tcg_temp_new_internal_i64(1); +} +void tcg_temp_free_i64(TCGv_i64 arg); +char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg); + +void tcg_dump_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + +#define TCG_CT_ALIAS 0x80 +#define TCG_CT_IALIAS 0x40 +#define TCG_CT_REG 0x01 +#define TCG_CT_CONST 0x02 /* any constant of register size */ + +typedef struct TCGArgConstraint { + uint16_t ct; + uint8_t alias_index; + union { + TCGRegSet regs; + } u; +} TCGArgConstraint; + +#define TCG_MAX_OP_ARGS 16 + +#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic + block */ +#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers + and potentially update globals. */ +#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it + cannot be removed if its output + are not used */ + +typedef struct TCGOpDef { + const char *name; + uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args; + uint8_t flags; + uint16_t copy_size; + TCGArgConstraint *args_ct; + int *sorted_args; +} TCGOpDef; + +typedef struct TCGTargetOpDef { + int op; + const char *args_ct_str[TCG_MAX_OP_ARGS]; +} TCGTargetOpDef; + +void tcg_target_init(TCGContext *s); +void tcg_target_qemu_prologue(TCGContext *s); + +#define tcg_abort() \ +do {\ + fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\ + abort();\ +} while (0) + +void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs); + +#if TCG_TARGET_REG_BITS == 32 +#define tcg_const_ptr tcg_const_i32 +#define tcg_add_ptr tcg_add_i32 +#define tcg_sub_ptr tcg_sub_i32 +#define TCGv_ptr TCGv_i32 +#define GET_TCGV_PTR GET_TCGV_I32 +#define tcg_global_reg_new_ptr tcg_global_reg_new_i32 +#define tcg_global_mem_new_ptr tcg_global_mem_new_i32 +#define tcg_temp_new_ptr tcg_temp_new_i32 +#define tcg_temp_free_ptr tcg_temp_free_i32 +#else +#define tcg_const_ptr tcg_const_i64 +#define tcg_add_ptr tcg_add_i64 +#define tcg_sub_ptr tcg_sub_i64 +#define TCGv_ptr TCGv_i64 +#define GET_TCGV_PTR GET_TCGV_I64 +#define tcg_global_reg_new_ptr tcg_global_reg_new_i64 +#define tcg_global_mem_new_ptr tcg_global_mem_new_i64 +#define tcg_temp_new_ptr tcg_temp_new_i64 +#define tcg_temp_free_ptr tcg_temp_free_i64 +#endif + +void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, + int sizemask, TCGArg ret, int nargs, TCGArg *args); + +void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, + int c, int right, int arith); + +/* only used for debugging purposes */ +void tcg_register_helper(void *func, const char *name); +const char *tcg_helper_get_name(TCGContext *s, void *func); +void tcg_dump_ops(TCGContext *s, FILE *outfile); + +void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf); +TCGv_i32 tcg_const_i32(int32_t val); +TCGv_i64 tcg_const_i64(int64_t val); +TCGv_i32 tcg_const_local_i32(int32_t val); +TCGv_i64 tcg_const_local_i64(int64_t val); + +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend); + +extern uint8_t code_gen_prologue[]; +#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64) +#define tcg_qemu_tb_exec(tb_ptr) \ + ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr) +#else +#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) +#endif diff --git a/qemu/qemu-git/tcg/x86_64/.svn/all-wcprops b/qemu/qemu-git/tcg/x86_64/.svn/all-wcprops new file mode 100644 index 0000000..682e45d --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 50 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/x86_64 +END +tcg-target.c +K 25 +svn:wc:ra_dav:version-url +V 63 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/x86_64/tcg-target.c +END +tcg-target.h +K 25 +svn:wc:ra_dav:version-url +V 63 +/p/x49gp/code/!svn/ver/10/qemu/qemu-git/tcg/x86_64/tcg-target.h +END diff --git a/qemu/qemu-git/tcg/x86_64/.svn/entries b/qemu/qemu-git/tcg/x86_64/.svn/entries new file mode 100644 index 0000000..fb06525 --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/qemu/qemu-git/tcg/x86_64 +http://svn.code.sf.net/p/x49gp/code + + + +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +tcg-target.c +file + + + + +2013-08-23T00:54:47.000000Z +d3f45a7da549459996584a45dd0890e2 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +41621 + +tcg-target.h +file + + + + +2013-08-23T00:54:47.000000Z +1838eb6151ae652ab32eec55d0b3a066 +2010-04-24T23:27:43.537348Z +10 +datajerk + + + + + + + + + + + + + + + + + + + + + +2768 + diff --git a/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.c.svn-base b/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.c.svn-base new file mode 100644 index 0000000..cbaabef --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.c.svn-base @@ -0,0 +1,1422 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%rax", + "%rcx", + "%rdx", + "%rbx", + "%rsp", + "%rbp", + "%rsi", + "%rdi", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R9, + TCG_REG_R8, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_RAX, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_RDI, + TCG_REG_RSI, + TCG_REG_RDX, + TCG_REG_RCX, + TCG_REG_R8, + TCG_REG_R9, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RAX, + TCG_REG_RDX +}; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_X86_64_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_X86_64_32S: + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + value -= (long)code_ptr; + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RCX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RSI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'e': + ct->ct |= TCG_CT_CONST_S32; + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) + return 1; + else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_ROL 0 +#define SHIFT_ROR 1 +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ +#define P_REXW 0x200 /* set rex.w = 1 */ +#define P_REXB_R 0x400 /* REG field as byte register */ +#define P_REXB_RM 0x800 /* R/M field as byte register */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x) +{ + int rex = 0; + + rex |= (opc & P_REXW) >> 6; /* REX.W */ + rex |= (r & 8) >> 1; /* REX.R */ + rex |= (x & 8) >> 2; /* REX.X */ + rex |= (rm & 8) >> 3; /* REX.B */ + + /* P_REXB_{R,RM} indicates that the given register is the low byte. + For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do, + as otherwise the encoding indicates %[abcd]h. Note that the values + that are ORed in merely indicate that the REX byte must be present; + those bits get discarded in output. */ + rex |= opc & (r >= 4 ? P_REXB_R : 0); + rex |= opc & (rm >= 4 ? P_REXB_RM : 0); + + if (rex) { + tcg_out8(s, (uint8_t)(rex | 0x40)); + } + if (opc & P_EXT) { + tcg_out8(s, 0x0f); + } + tcg_out8(s, opc & 0xff); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc, r, rm, 0); + tcg_out8(s, 0xc0 | ((r & 7) << 3) | (rm & 7)); +} + +/* rm < 0 means no register index plus (-rm - 1 immediate bytes) */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + tcg_target_long offset) +{ + if (rm < 0) { + tcg_target_long val; + tcg_out_opc(s, opc, r, 0, 0); + val = offset - ((tcg_target_long)s->code_ptr + 5 + (-rm - 1)); + if (val == (int32_t)val) { + /* eip relative */ + tcg_out8(s, 0x05 | ((r & 7) << 3)); + tcg_out32(s, val); + } else if (offset == (int32_t)offset) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x25); /* sib */ + tcg_out32(s, offset); + } else { + tcg_abort(); + } + } else if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | ((r & 7) << 3) | (rm & 7)); + } + } else if ((int8_t)offset == offset) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x44 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out8(s, offset); + } else { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x84 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out32(s, offset); + } +} + +#if defined(CONFIG_SOFTMMU) +/* XXX: incomplete. index must be different from ESP */ +static void tcg_out_modrm_offset2(TCGContext *s, int opc, int r, int rm, + int index, int shift, + tcg_target_long offset) +{ + int mod; + if (rm == -1) + tcg_abort(); + if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + mod = 0; + } else if (offset == (int8_t)offset) { + mod = 0x40; + } else if (offset == (int32_t)offset) { + mod = 0x80; + } else { + tcg_abort(); + } + if (index == -1) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, 0x04 | (rm & 7)); + } else { + tcg_out8(s, mod | ((r & 7) << 3) | (rm & 7)); + } + } else { + tcg_out_opc(s, opc, r, rm, index); + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, (shift << 6) | ((index & 7) << 3) | (rm & 7)); + } + if (mod == 0x40) { + tcg_out8(s, offset); + } else if (mod == 0x80) { + tcg_out32(s, offset); + } +} +#endif + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_modrm(s, 0x8b | P_REXW, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == 0) { + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); /* xor r0,r0 */ + } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) { + tcg_out_opc(s, 0xb8 + (ret & 7), 0, ret, 0); + tcg_out32(s, arg); + } else if (arg == (int32_t)arg) { + tcg_out_modrm(s, 0xc7 | P_REXW, 0, ret); + tcg_out32(s, arg); + } else { + tcg_out_opc(s, (0xb8 + (ret & 7)) | P_REXW, 0, ret, 0); + tcg_out32(s, arg); + tcg_out32(s, arg >> 32); + } +} + +static void tcg_out_goto(TCGContext *s, int call, uint8_t *target) +{ + int32_t disp; + + disp = target - s->code_ptr - 5; + if (disp == (target - s->code_ptr - 5)) { + tcg_out8(s, call ? 0xe8 : 0xe9); + tcg_out32(s, disp); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (tcg_target_long) target); + tcg_out_modrm(s, 0xff, call ? 2 : 4, TCG_REG_R10); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x8b | P_REXW, ret, arg1, arg2); /* movq */ +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x89 | P_REXW, arg, arg1, arg2); /* movq */ +} + +static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val) +{ + if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) { + /* inc */ + tcg_out_modrm(s, 0xff, 0, r0); + } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) { + /* dec */ + tcg_out_modrm(s, 0xff, 1, r0); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val) +{ + if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) { + /* inc */ + tcg_out_modrm(s, 0xff | P_REXW, 0, r0); + } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) { + /* dec */ + tcg_out_modrm(s, 0xff | P_REXW, 1, r0); + } else if (c == ARITH_AND && val == 0xffffffffu) { + /* 32-bit mov zero extends */ + tcg_out_modrm(s, 0x8b, r0, r0); + } else if (c == ARITH_AND && val == (uint32_t)val) { + /* AND with no high bits set can use a 32-bit operation. */ + tgen_arithi32(s, c, r0, (uint32_t)val); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83 | P_REXW, c, r0); + tcg_out8(s, val); + } else if (val == (int32_t)val) { + tcg_out_modrm(s, 0x81 | P_REXW, c, r0); + tcg_out32(s, val); + } else { + tcg_abort(); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi64(s, ARITH_ADD, reg, val); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int rexw) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85 | rexw, arg1, arg1); + } else { + if (rexw) + tgen_arithi64(s, ARITH_CMP, arg1, arg2); + else + tgen_arithi32(s, ARITH_CMP, arg1, arg2); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3) | rexw, arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index); + tcg_out_goto(s, 1, qemu_ld_helpers[s_bits]); + + switch(opc) { + case 0 | 4: + /* movsbq */ + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 1 | 4: + /* movswq */ + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 2 | 4: + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, TCG_REG_RAX); + break; + case 0: + /* movzbq */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 1: + /* movzwq */ + tcg_out_modrm(s, 0xb7 | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 2: + default: + /* movl */ + tcg_out_modrm(s, 0x8b, data_reg, TCG_REG_RAX); + break; + case 3: + tcg_out_mov(s, data_reg, TCG_REG_RAX); + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); + offset = 0; +#else + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset); + break; + case 0 | 4: + /* movsbX */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + if (bswap) { + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswX data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); + } else { + /* movswX */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + } + break; + case 2 | 4: + if (bswap) { + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); + } else { + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset); + } + break; + case 3: + /* movq (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, TCG_REG_RSI, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_RSI, data_reg); + break; + case 2: + /* movl */ + tcg_out_modrm(s, 0x8b, TCG_REG_RSI, data_reg); + break; + default: + case 3: + tcg_out_mov(s, TCG_REG_RSI, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); + tcg_out_goto(s, 1, qemu_st_helpers[s_bits]); + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); + offset = 0; +#else + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB_R, data_reg, r0, offset); + break; + case 1: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); + break; + case 2: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT, 0, r1, 0); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT | P_REXW, 0, r1, 0); + data_reg = r1; + } + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset); + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]); + tcg_out_goto(s, 0, tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out_goto(s, 1, (void *) args[0]); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_goto(s, 0, (void *) args[0]); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i64: + /* movsbq */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i64: + /* movswq */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_ld32s_i64: + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB_R, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith32; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith32; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith32; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith32; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith32: + if (const_args[2]) { + tgen_arithi32(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + + case INDEX_op_sub_i64: + c = ARITH_SUB; + goto gen_arith64; + case INDEX_op_and_i64: + c = ARITH_AND; + goto gen_arith64; + case INDEX_op_or_i64: + c = ARITH_OR; + goto gen_arith64; + case INDEX_op_xor_i64: + c = ARITH_XOR; + goto gen_arith64; + case INDEX_op_add_i64: + c = ARITH_ADD; + gen_arith64: + if (const_args[2]) { + tgen_arithi64(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3) | P_REXW, args[2], args[0]); + } + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mul_i64: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b | P_REXW, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69 | P_REXW, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT | P_REXW, args[0], args[2]); + } + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_div2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 7, args[4]); + break; + case INDEX_op_divu2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 6, args[4]); + break; + + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + case INDEX_op_rotl_i32: + c = SHIFT_ROL; + goto gen_shift32; + case INDEX_op_rotr_i32: + c = SHIFT_ROR; + goto gen_shift32; + + case INDEX_op_shl_i64: + c = SHIFT_SHL; + gen_shift64: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1 | P_REXW, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1 | P_REXW, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3 | P_REXW, c, args[0]); + } + break; + case INDEX_op_shr_i64: + c = SHIFT_SHR; + goto gen_shift64; + case INDEX_op_sar_i64: + c = SHIFT_SAR; + goto gen_shift64; + case INDEX_op_rotl_i64: + c = SHIFT_ROL; + goto gen_shift64; + case INDEX_op_rotr_i64: + c = SHIFT_ROR; + goto gen_shift64; + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], 0); + break; + case INDEX_op_brcond_i64: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], P_REXW); + break; + + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]); + tcg_out8(s, 8); + break; + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT, 0, args[0], 0); + break; + case INDEX_op_bswap64_i64: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT | P_REXW, 0, args[0], 0); + break; + + case INDEX_op_neg_i32: + tcg_out_modrm(s, 0xf7, 3, args[0]); + break; + case INDEX_op_neg_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 3, args[0]); + break; + + case INDEX_op_not_i32: + tcg_out_modrm(s, 0xf7, 2, args[0]); + break; + case INDEX_op_not_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 2, args[0]); + break; + + case INDEX_op_ext8s_i32: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXB_RM, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext8s_i64: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext16s_i64: + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext32s_i64: + tcg_out_modrm(s, 0x63 | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext8u_i32: + case INDEX_op_ext8u_i64: + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, args[0], args[1]); + break; + case INDEX_op_ext16u_i32: + case INDEX_op_ext16u_i64: + tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext32u_i64: + tcg_out_modrm(s, 0x8b, args[0], args[1]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static int tcg_target_callee_save_regs[] = { + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + /* TCG_REG_R14, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R15, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + + } + /* reserve some stack space */ + push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_RSP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_RSP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +static const TCGTargetOpDef x86_64_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_jmp, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + { INDEX_op_rotl_i32, { "r", "0", "ci" } }, + { INDEX_op_rotr_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_mul_i64, { "r", "0", "re" } }, + { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i64, { "r", "0", "re" } }, + { INDEX_op_and_i64, { "r", "0", "reZ" } }, + { INDEX_op_or_i64, { "r", "0", "re" } }, + { INDEX_op_xor_i64, { "r", "0", "re" } }, + + { INDEX_op_shl_i64, { "r", "0", "ci" } }, + { INDEX_op_shr_i64, { "r", "0", "ci" } }, + { INDEX_op_sar_i64, { "r", "0", "ci" } }, + { INDEX_op_rotl_i64, { "r", "0", "ci" } }, + { INDEX_op_rotr_i64, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i64, { "r", "re" } }, + + { INDEX_op_bswap16_i32, { "r", "0" } }, + { INDEX_op_bswap16_i64, { "r", "0" } }, + { INDEX_op_bswap32_i32, { "r", "0" } }, + { INDEX_op_bswap32_i64, { "r", "0" } }, + { INDEX_op_bswap64_i64, { "r", "0" } }, + + { INDEX_op_neg_i32, { "r", "0" } }, + { INDEX_op_neg_i64, { "r", "0" } }, + + { INDEX_op_not_i32, { "r", "0" } }, + { INDEX_op_not_i64, { "r", "0" } }, + + { INDEX_op_ext8s_i32, { "r", "r"} }, + { INDEX_op_ext16s_i32, { "r", "r"} }, + { INDEX_op_ext8s_i64, { "r", "r"} }, + { INDEX_op_ext16s_i64, { "r", "r"} }, + { INDEX_op_ext32s_i64, { "r", "r"} }, + { INDEX_op_ext8u_i32, { "r", "r"} }, + { INDEX_op_ext16u_i32, { "r", "r"} }, + { INDEX_op_ext8u_i64, { "r", "r"} }, + { INDEX_op_ext16u_i64, { "r", "r"} }, + { INDEX_op_ext32u_i64, { "r", "r"} }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_RDI) | + (1 << TCG_REG_RSI) | + (1 << TCG_REG_RDX) | + (1 << TCG_REG_RCX) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_RAX) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP); + + tcg_add_target_add_op_defs(x86_64_op_defs); +} diff --git a/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.h.svn-base b/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.h.svn-base new file mode 100644 index 0000000..3ca392f --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/.svn/text-base/tcg-target.h.svn-base @@ -0,0 +1,91 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_X86_64 1 + +#define TCG_TARGET_REG_BITS 64 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 16 + +enum { + TCG_REG_RAX = 0, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RBX, + TCG_REG_RSP, + TCG_REG_RBP, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, +}; + +#define TCG_CT_CONST_S32 0x100 +#define TCG_CT_CONST_U32 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_RSP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_bswap16_i32 +#define TCG_TARGET_HAS_bswap16_i64 +#define TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_bswap32_i64 +#define TCG_TARGET_HAS_bswap64_i64 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_not_i32 +#define TCG_TARGET_HAS_not_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 +#define TCG_TARGET_HAS_ext8u_i32 +#define TCG_TARGET_HAS_ext16u_i32 +#define TCG_TARGET_HAS_ext8u_i64 +#define TCG_TARGET_HAS_ext16u_i64 +#define TCG_TARGET_HAS_ext32u_i64 + +#define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_rot_i64 + +#define TCG_TARGET_HAS_GUEST_BASE + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R14 +#define TCG_AREG1 TCG_REG_R15 +#define TCG_AREG2 TCG_REG_R12 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/qemu-git/tcg/x86_64/tcg-target.c b/qemu/qemu-git/tcg/x86_64/tcg-target.c new file mode 100644 index 0000000..cbaabef --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/tcg-target.c @@ -0,0 +1,1422 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%rax", + "%rcx", + "%rdx", + "%rbx", + "%rsp", + "%rbp", + "%rsi", + "%rdi", + "%r8", + "%r9", + "%r10", + "%r11", + "%r12", + "%r13", + "%r14", + "%r15", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R9, + TCG_REG_R8, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_RAX, +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_RDI, + TCG_REG_RSI, + TCG_REG_RDX, + TCG_REG_RCX, + TCG_REG_R8, + TCG_REG_R9, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_RAX, + TCG_REG_RDX +}; + +static uint8_t *tb_ret_addr; + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + switch(type) { + case R_X86_64_32: + if (value != (uint32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_X86_64_32S: + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + case R_386_PC32: + value -= (long)code_ptr; + if (value != (int32_t)value) + tcg_abort(); + *(uint32_t *)code_ptr = value; + break; + default: + tcg_abort(); + } +} + +/* maximum number of register used for input function arguments */ +static inline int tcg_target_get_call_iarg_regs_count(int flags) +{ + return 6; +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch(ct_str[0]) { + case 'a': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RAX); + break; + case 'b': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RBX); + break; + case 'c': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RCX); + break; + case 'd': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDX); + break; + case 'S': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RSI); + break; + case 'D': + ct->ct |= TCG_CT_REG; + tcg_regset_set_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI); + break; + case 'e': + ct->ct |= TCG_CT_CONST_S32; + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) + return 1; + else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) + return 1; + else + return 0; +} + +#define ARITH_ADD 0 +#define ARITH_OR 1 +#define ARITH_ADC 2 +#define ARITH_SBB 3 +#define ARITH_AND 4 +#define ARITH_SUB 5 +#define ARITH_XOR 6 +#define ARITH_CMP 7 + +#define SHIFT_ROL 0 +#define SHIFT_ROR 1 +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#define JCC_JMP (-1) +#define JCC_JO 0x0 +#define JCC_JNO 0x1 +#define JCC_JB 0x2 +#define JCC_JAE 0x3 +#define JCC_JE 0x4 +#define JCC_JNE 0x5 +#define JCC_JBE 0x6 +#define JCC_JA 0x7 +#define JCC_JS 0x8 +#define JCC_JNS 0x9 +#define JCC_JP 0xa +#define JCC_JNP 0xb +#define JCC_JL 0xc +#define JCC_JGE 0xd +#define JCC_JLE 0xe +#define JCC_JG 0xf + +#define P_EXT 0x100 /* 0x0f opcode prefix */ +#define P_REXW 0x200 /* set rex.w = 1 */ +#define P_REXB_R 0x400 /* REG field as byte register */ +#define P_REXB_RM 0x800 /* R/M field as byte register */ + +static const uint8_t tcg_cond_to_jcc[10] = { + [TCG_COND_EQ] = JCC_JE, + [TCG_COND_NE] = JCC_JNE, + [TCG_COND_LT] = JCC_JL, + [TCG_COND_GE] = JCC_JGE, + [TCG_COND_LE] = JCC_JLE, + [TCG_COND_GT] = JCC_JG, + [TCG_COND_LTU] = JCC_JB, + [TCG_COND_GEU] = JCC_JAE, + [TCG_COND_LEU] = JCC_JBE, + [TCG_COND_GTU] = JCC_JA, +}; + +static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x) +{ + int rex = 0; + + rex |= (opc & P_REXW) >> 6; /* REX.W */ + rex |= (r & 8) >> 1; /* REX.R */ + rex |= (x & 8) >> 2; /* REX.X */ + rex |= (rm & 8) >> 3; /* REX.B */ + + /* P_REXB_{R,RM} indicates that the given register is the low byte. + For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do, + as otherwise the encoding indicates %[abcd]h. Note that the values + that are ORed in merely indicate that the REX byte must be present; + those bits get discarded in output. */ + rex |= opc & (r >= 4 ? P_REXB_R : 0); + rex |= opc & (rm >= 4 ? P_REXB_RM : 0); + + if (rex) { + tcg_out8(s, (uint8_t)(rex | 0x40)); + } + if (opc & P_EXT) { + tcg_out8(s, 0x0f); + } + tcg_out8(s, opc & 0xff); +} + +static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm) +{ + tcg_out_opc(s, opc, r, rm, 0); + tcg_out8(s, 0xc0 | ((r & 7) << 3) | (rm & 7)); +} + +/* rm < 0 means no register index plus (-rm - 1 immediate bytes) */ +static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm, + tcg_target_long offset) +{ + if (rm < 0) { + tcg_target_long val; + tcg_out_opc(s, opc, r, 0, 0); + val = offset - ((tcg_target_long)s->code_ptr + 5 + (-rm - 1)); + if (val == (int32_t)val) { + /* eip relative */ + tcg_out8(s, 0x05 | ((r & 7) << 3)); + tcg_out32(s, val); + } else if (offset == (int32_t)offset) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x25); /* sib */ + tcg_out32(s, offset); + } else { + tcg_abort(); + } + } else if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x04 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x00 | ((r & 7) << 3) | (rm & 7)); + } + } else if ((int8_t)offset == offset) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x44 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x40 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out8(s, offset); + } else { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, 0x84 | ((r & 7) << 3)); + tcg_out8(s, 0x24); + } else { + tcg_out8(s, 0x80 | ((r & 7) << 3) | (rm & 7)); + } + tcg_out32(s, offset); + } +} + +#if defined(CONFIG_SOFTMMU) +/* XXX: incomplete. index must be different from ESP */ +static void tcg_out_modrm_offset2(TCGContext *s, int opc, int r, int rm, + int index, int shift, + tcg_target_long offset) +{ + int mod; + if (rm == -1) + tcg_abort(); + if (offset == 0 && (rm & 7) != TCG_REG_RBP) { + mod = 0; + } else if (offset == (int8_t)offset) { + mod = 0x40; + } else if (offset == (int32_t)offset) { + mod = 0x80; + } else { + tcg_abort(); + } + if (index == -1) { + tcg_out_opc(s, opc, r, rm, 0); + if ((rm & 7) == TCG_REG_RSP) { + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, 0x04 | (rm & 7)); + } else { + tcg_out8(s, mod | ((r & 7) << 3) | (rm & 7)); + } + } else { + tcg_out_opc(s, opc, r, rm, index); + tcg_out8(s, mod | ((r & 7) << 3) | 0x04); + tcg_out8(s, (shift << 6) | ((index & 7) << 3) | (rm & 7)); + } + if (mod == 0x40) { + tcg_out8(s, offset); + } else if (mod == 0x80) { + tcg_out32(s, offset); + } +} +#endif + +static inline void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_out_modrm(s, 0x8b | P_REXW, ret, arg); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + if (arg == 0) { + tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); /* xor r0,r0 */ + } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) { + tcg_out_opc(s, 0xb8 + (ret & 7), 0, ret, 0); + tcg_out32(s, arg); + } else if (arg == (int32_t)arg) { + tcg_out_modrm(s, 0xc7 | P_REXW, 0, ret); + tcg_out32(s, arg); + } else { + tcg_out_opc(s, (0xb8 + (ret & 7)) | P_REXW, 0, ret, 0); + tcg_out32(s, arg); + tcg_out32(s, arg >> 32); + } +} + +static void tcg_out_goto(TCGContext *s, int call, uint8_t *target) +{ + int32_t disp; + + disp = target - s->code_ptr - 5; + if (disp == (target - s->code_ptr - 5)) { + tcg_out8(s, call ? 0xe8 : 0xe9); + tcg_out32(s, disp); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (tcg_target_long) target); + tcg_out_modrm(s, 0xff, call ? 2 : 4, TCG_REG_R10); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x8b | P_REXW, ret, arg1, arg2); /* movq */ +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, + int arg1, tcg_target_long arg2) +{ + if (type == TCG_TYPE_I32) + tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); /* movl */ + else + tcg_out_modrm_offset(s, 0x89 | P_REXW, arg, arg1, arg2); /* movq */ +} + +static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val) +{ + if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) { + /* inc */ + tcg_out_modrm(s, 0xff, 0, r0); + } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) { + /* dec */ + tcg_out_modrm(s, 0xff, 1, r0); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83, c, r0); + tcg_out8(s, val); + } else if (c == ARITH_AND && val == 0xffu) { + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, r0, r0); + } else if (c == ARITH_AND && val == 0xffffu) { + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0); + } else { + tcg_out_modrm(s, 0x81, c, r0); + tcg_out32(s, val); + } +} + +static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val) +{ + if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) { + /* inc */ + tcg_out_modrm(s, 0xff | P_REXW, 0, r0); + } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) { + /* dec */ + tcg_out_modrm(s, 0xff | P_REXW, 1, r0); + } else if (c == ARITH_AND && val == 0xffffffffu) { + /* 32-bit mov zero extends */ + tcg_out_modrm(s, 0x8b, r0, r0); + } else if (c == ARITH_AND && val == (uint32_t)val) { + /* AND with no high bits set can use a 32-bit operation. */ + tgen_arithi32(s, c, r0, (uint32_t)val); + } else if (val == (int8_t)val) { + tcg_out_modrm(s, 0x83 | P_REXW, c, r0); + tcg_out8(s, val); + } else if (val == (int32_t)val) { + tcg_out_modrm(s, 0x81 | P_REXW, c, r0); + tcg_out32(s, val); + } else { + tcg_abort(); + } +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + if (val != 0) + tgen_arithi64(s, ARITH_ADD, reg, val); +} + +static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +{ + int32_t val, val1; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + val1 = val - 2; + if ((int8_t)val1 == val1) { + if (opc == -1) + tcg_out8(s, 0xeb); + else + tcg_out8(s, 0x70 + opc); + tcg_out8(s, val1); + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + tcg_out32(s, val - 5); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + tcg_out32(s, val - 6); + } + } + } else { + if (opc == -1) { + tcg_out8(s, 0xe9); + } else { + tcg_out8(s, 0x0f); + tcg_out8(s, 0x80 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4); + s->code_ptr += 4; + } +} + +static void tcg_out_brcond(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index, int rexw) +{ + if (const_arg2) { + if (arg2 == 0) { + /* test r, r */ + tcg_out_modrm(s, 0x85 | rexw, arg1, arg1); + } else { + if (rexw) + tgen_arithi64(s, ARITH_CMP, arg1, arg2); + else + tgen_arithi32(s, ARITH_CMP, arg1, arg2); + } + } else { + tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3) | rexw, arg2, arg1); + } + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); +} + +#if defined(CONFIG_SOFTMMU) + +#include "../../softmmu_defs.h" + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_read)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index); + tcg_out_goto(s, 1, qemu_ld_helpers[s_bits]); + + switch(opc) { + case 0 | 4: + /* movsbq */ + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 1 | 4: + /* movswq */ + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 2 | 4: + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, TCG_REG_RAX); + break; + case 0: + /* movzbq */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 1: + /* movzwq */ + tcg_out_modrm(s, 0xb7 | P_EXT | P_REXW, data_reg, TCG_REG_RAX); + break; + case 2: + default: + /* movl */ + tcg_out_modrm(s, 0x8b, data_reg, TCG_REG_RAX); + break; + case 3: + tcg_out_mov(s, data_reg, TCG_REG_RAX); + break; + } + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read)); + offset = 0; +#else + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset); + break; + case 0 | 4: + /* movsbX */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset); + break; + case 1: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); + if (bswap) { + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + } + break; + case 1 | 4: + if (bswap) { + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); + /* rolw $8, data_reg */ + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, 0, data_reg); + tcg_out8(s, 8); + + /* movswX data_reg, data_reg */ + tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); + } else { + /* movswX */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset); + } + break; + case 2: + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + } + break; + case 2 | 4: + if (bswap) { + /* movl (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); + /* movslq */ + tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); + } else { + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset); + } + break; + case 3: + /* movq (r0), data_reg */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset); + if (bswap) { + /* bswap */ + tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; + int32_t offset; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_RDI; + r1 = TCG_REG_RSI; + +#if TARGET_LONG_BITS == 32 + rexw = 0; +#else + rexw = P_REXW; +#endif +#if defined(CONFIG_SOFTMMU) + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */ + tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + + tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */ + tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */ + tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + + /* lea offset(r1, env), r1 */ + tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0, + offsetof(CPUState, tlb_table[mem_index][0].addr_write)); + + /* cmp 0(r1), r0 */ + tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0); + + /* mov */ + tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); + + /* je label1 */ + tcg_out8(s, 0x70 + JCC_JE); + label1_ptr = s->code_ptr; + s->code_ptr++; + + /* XXX: move that code at the end of the TB */ + switch(opc) { + case 0: + /* movzbl */ + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, TCG_REG_RSI, data_reg); + break; + case 1: + /* movzwl */ + tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_RSI, data_reg); + break; + case 2: + /* movl */ + tcg_out_modrm(s, 0x8b, TCG_REG_RSI, data_reg); + break; + default: + case 3: + tcg_out_mov(s, TCG_REG_RSI, data_reg); + break; + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); + tcg_out_goto(s, 1, qemu_st_helpers[s_bits]); + + /* jmp label2 */ + tcg_out8(s, 0xeb); + label2_ptr = s->code_ptr; + s->code_ptr++; + + /* label1: */ + *label1_ptr = s->code_ptr - label1_ptr - 1; + + /* add x(r1), r0 */ + tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write)); + offset = 0; +#else + if (GUEST_BASE == (int32_t)GUEST_BASE) { + r0 = addr_reg; + offset = GUEST_BASE; + } else { + offset = 0; + /* movq $GUEST_BASE, r0 */ + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); + tcg_out32(s, GUEST_BASE); + tcg_out32(s, GUEST_BASE >> 32); + /* addq addr_reg, r0 */ + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); + } +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 1; +#else + bswap = 0; +#endif + switch(opc) { + case 0: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB_R, data_reg, r0, offset); + break; + case 1: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + tcg_out8(s, 0x66); /* rolw $8, %ecx */ + tcg_out_modrm(s, 0xc1, 0, r1); + tcg_out8(s, 8); + data_reg = r1; + } + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); + break; + case 2: + if (bswap) { + tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */ + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT, 0, r1, 0); + data_reg = r1; + } + /* movl */ + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); + break; + case 3: + if (bswap) { + tcg_out_mov(s, r1, data_reg); + /* bswap data_reg */ + tcg_out_opc(s, (0xc8 + r1) | P_EXT | P_REXW, 0, r1, 0); + data_reg = r1; + } + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset); + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = s->code_ptr - label2_ptr - 1; +#endif +} + +static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + int c; + + switch(opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]); + tcg_out_goto(s, 0, tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ + tcg_out8(s, 0xe9); /* jmp im */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + tcg_out32(s, 0); + } else { + /* indirect jump method */ + /* jmp Ev */ + tcg_out_modrm_offset(s, 0xff, 4, -1, + (tcg_target_long)(s->tb_next + + args[0])); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: + if (const_args[0]) { + tcg_out_goto(s, 1, (void *) args[0]); + } else { + tcg_out_modrm(s, 0xff, 2, args[0]); + } + break; + case INDEX_op_jmp: + if (const_args[0]) { + tcg_out_goto(s, 0, (void *) args[0]); + } else { + tcg_out_modrm(s, 0xff, 4, args[0]); + } + break; + case INDEX_op_br: + tcg_out_jxx(s, JCC_JMP, args[0]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); + break; + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + /* movzbl */ + tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + /* movsbl */ + tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i64: + /* movsbq */ + tcg_out_modrm_offset(s, 0xbe | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + /* movzwl */ + tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + /* movswl */ + tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i64: + /* movswq */ + tcg_out_modrm_offset(s, 0xbf | P_EXT | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]); + break; + case INDEX_op_ld32s_i64: + /* movslq */ + tcg_out_modrm_offset(s, 0x63 | P_REXW, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x8b | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + /* movb */ + tcg_out_modrm_offset(s, 0x88 | P_REXB_R, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + /* movw */ + tcg_out8(s, 0x66); + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + /* movl */ + tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]); + break; + case INDEX_op_st_i64: + /* movq */ + tcg_out_modrm_offset(s, 0x89 | P_REXW, args[0], args[1], args[2]); + break; + + case INDEX_op_sub_i32: + c = ARITH_SUB; + goto gen_arith32; + case INDEX_op_and_i32: + c = ARITH_AND; + goto gen_arith32; + case INDEX_op_or_i32: + c = ARITH_OR; + goto gen_arith32; + case INDEX_op_xor_i32: + c = ARITH_XOR; + goto gen_arith32; + case INDEX_op_add_i32: + c = ARITH_ADD; + gen_arith32: + if (const_args[2]) { + tgen_arithi32(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]); + } + break; + + case INDEX_op_sub_i64: + c = ARITH_SUB; + goto gen_arith64; + case INDEX_op_and_i64: + c = ARITH_AND; + goto gen_arith64; + case INDEX_op_or_i64: + c = ARITH_OR; + goto gen_arith64; + case INDEX_op_xor_i64: + c = ARITH_XOR; + goto gen_arith64; + case INDEX_op_add_i64: + c = ARITH_ADD; + gen_arith64: + if (const_args[2]) { + tgen_arithi64(s, c, args[0], args[2]); + } else { + tcg_out_modrm(s, 0x01 | (c << 3) | P_REXW, args[2], args[0]); + } + break; + + case INDEX_op_mul_i32: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]); + } + break; + case INDEX_op_mul_i64: + if (const_args[2]) { + int32_t val; + val = args[2]; + if (val == (int8_t)val) { + tcg_out_modrm(s, 0x6b | P_REXW, args[0], args[0]); + tcg_out8(s, val); + } else { + tcg_out_modrm(s, 0x69 | P_REXW, args[0], args[0]); + tcg_out32(s, val); + } + } else { + tcg_out_modrm(s, 0xaf | P_EXT | P_REXW, args[0], args[2]); + } + break; + case INDEX_op_div2_i32: + tcg_out_modrm(s, 0xf7, 7, args[4]); + break; + case INDEX_op_divu2_i32: + tcg_out_modrm(s, 0xf7, 6, args[4]); + break; + case INDEX_op_div2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 7, args[4]); + break; + case INDEX_op_divu2_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 6, args[4]); + break; + + case INDEX_op_shl_i32: + c = SHIFT_SHL; + gen_shift32: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3, c, args[0]); + } + break; + case INDEX_op_shr_i32: + c = SHIFT_SHR; + goto gen_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SAR; + goto gen_shift32; + case INDEX_op_rotl_i32: + c = SHIFT_ROL; + goto gen_shift32; + case INDEX_op_rotr_i32: + c = SHIFT_ROR; + goto gen_shift32; + + case INDEX_op_shl_i64: + c = SHIFT_SHL; + gen_shift64: + if (const_args[2]) { + if (args[2] == 1) { + tcg_out_modrm(s, 0xd1 | P_REXW, c, args[0]); + } else { + tcg_out_modrm(s, 0xc1 | P_REXW, c, args[0]); + tcg_out8(s, args[2]); + } + } else { + tcg_out_modrm(s, 0xd3 | P_REXW, c, args[0]); + } + break; + case INDEX_op_shr_i64: + c = SHIFT_SHR; + goto gen_shift64; + case INDEX_op_sar_i64: + c = SHIFT_SAR; + goto gen_shift64; + case INDEX_op_rotl_i64: + c = SHIFT_ROL; + goto gen_shift64; + case INDEX_op_rotr_i64: + c = SHIFT_ROR; + goto gen_shift64; + + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], 0); + break; + case INDEX_op_brcond_i64: + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], P_REXW); + break; + + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + tcg_out8(s, 0x66); + tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]); + tcg_out8(s, 8); + break; + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT, 0, args[0], 0); + break; + case INDEX_op_bswap64_i64: + tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT | P_REXW, 0, args[0], 0); + break; + + case INDEX_op_neg_i32: + tcg_out_modrm(s, 0xf7, 3, args[0]); + break; + case INDEX_op_neg_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 3, args[0]); + break; + + case INDEX_op_not_i32: + tcg_out_modrm(s, 0xf7, 2, args[0]); + break; + case INDEX_op_not_i64: + tcg_out_modrm(s, 0xf7 | P_REXW, 2, args[0]); + break; + + case INDEX_op_ext8s_i32: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXB_RM, args[0], args[1]); + break; + case INDEX_op_ext16s_i32: + tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext8s_i64: + tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext16s_i64: + tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext32s_i64: + tcg_out_modrm(s, 0x63 | P_REXW, args[0], args[1]); + break; + case INDEX_op_ext8u_i32: + case INDEX_op_ext8u_i64: + tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, args[0], args[1]); + break; + case INDEX_op_ext16u_i32: + case INDEX_op_ext16u_i64: + tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]); + break; + case INDEX_op_ext32u_i64: + tcg_out_modrm(s, 0x8b, args[0], args[1]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 0 | 4); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 1 | 4); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 3); + break; + + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + default: + tcg_abort(); + } +} + +static int tcg_target_callee_save_regs[] = { + TCG_REG_RBP, + TCG_REG_RBX, + TCG_REG_R12, + TCG_REG_R13, + /* TCG_REG_R14, */ /* currently used for the global env, so no + need to save */ + TCG_REG_R15, +}; + +static inline void tcg_out_push(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0); +} + +static inline void tcg_out_pop(TCGContext *s, int reg) +{ + tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0); +} + +/* Generate global QEMU prologue and epilogue code */ +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + + } + /* reserve some stack space */ + push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_RSP, -stack_addend); + + tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_RSP, stack_addend); + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { + tcg_out_pop(s, tcg_target_callee_save_regs[i]); + } + tcg_out8(s, 0xc3); /* ret */ +} + +static const TCGTargetOpDef x86_64_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_jmp, { "ri" } }, /* XXX: might need a specific constant constraint */ + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "0", "ri" } }, + { INDEX_op_mul_i32, { "r", "0", "ri" } }, + { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, + { INDEX_op_and_i32, { "r", "0", "ri" } }, + { INDEX_op_or_i32, { "r", "0", "ri" } }, + { INDEX_op_xor_i32, { "r", "0", "ri" } }, + + { INDEX_op_shl_i32, { "r", "0", "ci" } }, + { INDEX_op_shr_i32, { "r", "0", "ci" } }, + { INDEX_op_sar_i32, { "r", "0", "ci" } }, + { INDEX_op_rotl_i32, { "r", "0", "ci" } }, + { INDEX_op_rotr_i32, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i32, { "r", "ri" } }, + + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + + { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_mul_i64, { "r", "0", "re" } }, + { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } }, + { INDEX_op_sub_i64, { "r", "0", "re" } }, + { INDEX_op_and_i64, { "r", "0", "reZ" } }, + { INDEX_op_or_i64, { "r", "0", "re" } }, + { INDEX_op_xor_i64, { "r", "0", "re" } }, + + { INDEX_op_shl_i64, { "r", "0", "ci" } }, + { INDEX_op_shr_i64, { "r", "0", "ci" } }, + { INDEX_op_sar_i64, { "r", "0", "ci" } }, + { INDEX_op_rotl_i64, { "r", "0", "ci" } }, + { INDEX_op_rotr_i64, { "r", "0", "ci" } }, + + { INDEX_op_brcond_i64, { "r", "re" } }, + + { INDEX_op_bswap16_i32, { "r", "0" } }, + { INDEX_op_bswap16_i64, { "r", "0" } }, + { INDEX_op_bswap32_i32, { "r", "0" } }, + { INDEX_op_bswap32_i64, { "r", "0" } }, + { INDEX_op_bswap64_i64, { "r", "0" } }, + + { INDEX_op_neg_i32, { "r", "0" } }, + { INDEX_op_neg_i64, { "r", "0" } }, + + { INDEX_op_not_i32, { "r", "0" } }, + { INDEX_op_not_i64, { "r", "0" } }, + + { INDEX_op_ext8s_i32, { "r", "r"} }, + { INDEX_op_ext16s_i32, { "r", "r"} }, + { INDEX_op_ext8s_i64, { "r", "r"} }, + { INDEX_op_ext16s_i64, { "r", "r"} }, + { INDEX_op_ext32s_i64, { "r", "r"} }, + { INDEX_op_ext8u_i32, { "r", "r"} }, + { INDEX_op_ext16u_i32, { "r", "r"} }, + { INDEX_op_ext8u_i64, { "r", "r"} }, + { INDEX_op_ext16u_i64, { "r", "r"} }, + { INDEX_op_ext32u_i64, { "r", "r"} }, + + { INDEX_op_qemu_ld8u, { "r", "L" } }, + { INDEX_op_qemu_ld8s, { "r", "L" } }, + { INDEX_op_qemu_ld16u, { "r", "L" } }, + { INDEX_op_qemu_ld16s, { "r", "L" } }, + { INDEX_op_qemu_ld32u, { "r", "L" } }, + { INDEX_op_qemu_ld32s, { "r", "L" } }, + { INDEX_op_qemu_ld64, { "r", "L" } }, + + { INDEX_op_qemu_st8, { "L", "L" } }, + { INDEX_op_qemu_st16, { "L", "L" } }, + { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_RDI) | + (1 << TCG_REG_RSI) | + (1 << TCG_REG_RDX) | + (1 << TCG_REG_RCX) | + (1 << TCG_REG_R8) | + (1 << TCG_REG_R9) | + (1 << TCG_REG_RAX) | + (1 << TCG_REG_R10) | + (1 << TCG_REG_R11)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP); + + tcg_add_target_add_op_defs(x86_64_op_defs); +} diff --git a/qemu/qemu-git/tcg/x86_64/tcg-target.h b/qemu/qemu-git/tcg/x86_64/tcg-target.h new file mode 100644 index 0000000..3ca392f --- /dev/null +++ b/qemu/qemu-git/tcg/x86_64/tcg-target.h @@ -0,0 +1,91 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define TCG_TARGET_X86_64 1 + +#define TCG_TARGET_REG_BITS 64 +//#define TCG_TARGET_WORDS_BIGENDIAN + +#define TCG_TARGET_NB_REGS 16 + +enum { + TCG_REG_RAX = 0, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RBX, + TCG_REG_RSP, + TCG_REG_RBP, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R14, + TCG_REG_R15, +}; + +#define TCG_CT_CONST_S32 0x100 +#define TCG_CT_CONST_U32 0x200 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_RSP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_bswap16_i32 +#define TCG_TARGET_HAS_bswap16_i64 +#define TCG_TARGET_HAS_bswap32_i32 +#define TCG_TARGET_HAS_bswap32_i64 +#define TCG_TARGET_HAS_bswap64_i64 +#define TCG_TARGET_HAS_neg_i32 +#define TCG_TARGET_HAS_neg_i64 +#define TCG_TARGET_HAS_not_i32 +#define TCG_TARGET_HAS_not_i64 +#define TCG_TARGET_HAS_ext8s_i32 +#define TCG_TARGET_HAS_ext16s_i32 +#define TCG_TARGET_HAS_ext8s_i64 +#define TCG_TARGET_HAS_ext16s_i64 +#define TCG_TARGET_HAS_ext32s_i64 +#define TCG_TARGET_HAS_ext8u_i32 +#define TCG_TARGET_HAS_ext16u_i32 +#define TCG_TARGET_HAS_ext8u_i64 +#define TCG_TARGET_HAS_ext16u_i64 +#define TCG_TARGET_HAS_ext32u_i64 + +#define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_rot_i64 + +#define TCG_TARGET_HAS_GUEST_BASE + +/* Note: must be synced with dyngen-exec.h */ +#define TCG_AREG0 TCG_REG_R14 +#define TCG_AREG1 TCG_REG_R15 +#define TCG_AREG2 TCG_REG_R12 + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/qemu-git/translate-all.c b/qemu/qemu-git/translate-all.c new file mode 100644 index 0000000..8ef8a0b --- /dev/null +++ b/qemu/qemu-git/translate-all.c @@ -0,0 +1,194 @@ +/* + * Host code generation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include +#include +#include +#include +#include + +#include "config.h" + +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg.h" + +/* code generation context */ +TCGContext tcg_ctx; + +uint16_t gen_opc_buf[OPC_BUF_SIZE]; +TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; + +target_ulong gen_opc_pc[OPC_BUF_SIZE]; +uint16_t gen_opc_icount[OPC_BUF_SIZE]; +uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +#if defined(TARGET_I386) +uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +#elif defined(TARGET_SPARC) +target_ulong gen_opc_npc[OPC_BUF_SIZE]; +target_ulong gen_opc_jump_pc[2]; +#elif defined(TARGET_MIPS) || defined(TARGET_SH4) +uint32_t gen_opc_hflags[OPC_BUF_SIZE]; +#endif + +/* XXX: suppress that */ +unsigned long code_gen_max_block_size(void) +{ + static unsigned long max; + + if (max == 0) { + max = TCG_MAX_OP_SIZE; +#define DEF(s, n, copy_size) max = copy_size > max? copy_size : max; +#include "tcg-opc.h" +#undef DEF + max *= OPC_MAX_SIZE; + } + + return max; +} + +void cpu_gen_init(void) +{ + tcg_context_init(&tcg_ctx); + tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); +} + +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ +int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) +{ + TCGContext *s = &tcg_ctx; + uint8_t *gen_code_buf; + int gen_code_size; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + +#ifdef CONFIG_PROFILER + s->tb_count1++; /* includes aborted translations because of + exceptions */ + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code(env, tb); + + /* generate machine code */ + gen_code_buf = tb->tc_ptr; + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + s->tb_next_offset = tb->tb_next_offset; +#ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; + /* the following two entries are optional (only used for string ops) */ + /* XXX: not used ? */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; +#else + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; +#endif + +#ifdef CONFIG_PROFILER + s->tb_count++; + s->interm_time += profile_getclock() - ti; + s->code_time -= profile_getclock(); +#endif + gen_code_size = tcg_gen_code(s, gen_code_buf); + *gen_code_size_ptr = gen_code_size; +#ifdef CONFIG_PROFILER + s->code_time += profile_getclock(); + s->code_in_len += tb->size; + s->code_out_len += gen_code_size; +#endif + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { + qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr); + log_disas(tb->tc_ptr, *gen_code_size_ptr); + qemu_log("\n"); + qemu_log_flush(); + } +#endif + return 0; +} + +/* The cpu state corresponding to 'searched_pc' is restored. + */ +int cpu_restore_state(TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc) +{ + TCGContext *s = &tcg_ctx; + int j; + unsigned long tc_ptr; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif + tcg_func_start(s); + + gen_intermediate_code_pc(env, tb); + + if (use_icount) { + /* Reset the cycle counter to the start of the block. */ + env->icount_decr.u16.low += tb->icount; + /* Clear the IO flag. */ + env->can_do_io = 0; + } + + /* find opc index corresponding to search_pc */ + tc_ptr = (unsigned long)tb->tc_ptr; + if (searched_pc < tc_ptr) + return -1; + + s->tb_next_offset = tb->tb_next_offset; +#ifdef USE_DIRECT_JUMP + s->tb_jmp_offset = tb->tb_jmp_offset; + s->tb_next = NULL; +#else + s->tb_jmp_offset = NULL; + s->tb_next = tb->tb_next; +#endif + j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr); + if (j < 0) + return -1; + /* now find start of instruction before */ + while (gen_opc_instr_start[j] == 0) + j--; + env->icount_decr.u16.low -= gen_opc_icount[j]; + + gen_pc_load(env, tb, searched_pc, j, puc); + +#ifdef CONFIG_PROFILER + s->restore_time += profile_getclock() - ti; + s->restore_count++; +#endif + return 0; +} diff --git a/qemu/qemu-git/x86_64.ld b/qemu/qemu-git/x86_64.ld new file mode 100644 index 0000000..24ea77d --- /dev/null +++ b/qemu/qemu-git/x86_64.ld @@ -0,0 +1,170 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/s3c2410.c b/s3c2410.c new file mode 100644 index 0000000..b587f6e --- /dev/null +++ b/s3c2410.c @@ -0,0 +1,67 @@ +/* $Id: s3c2410.c,v 1.38 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Boot SRAM: 0x40000000 + * Memory Controller: 0x48000000 + * USB Host: 0x49000000 + * Interrupt Controller: 0x4a000000 + * DMA: 0x4b000000 + * Clock and Power Management: 0x4c000000 + * LCD Controller: 0x4d000000 + * NAND Flash Controller: 0x4e000000 + * UART: 0x50000000 + * PWM Timers: 0x51000000 + * USB Device: 0x52000000 + * Watchdog: 0x53000000 + * I2C Master: 0x54000000 + * IIS Interface: 0x55000000 + * GPIO Ports: 0x56000000 + * RTC: 0x57000000 + * ADC Controller: 0x58000000 + * SPI Interface: 0x59000000 + * SDI Interface: 0x5a000000 + */ +int +x49gp_s3c2410_init(x49gp_t *x49gp) +{ + x49gp_s3c2410_sram_init(x49gp); + x49gp_s3c2410_memc_init(x49gp); + /* x49gp_s3c2410_usbhost_init(x49gp); */ + x49gp_s3c2410_intc_init(x49gp); + /* x49gp_s3c2410_dma_init(x49gp); */ + x49gp_s3c2410_power_init(x49gp); + x49gp_s3c2410_lcd_init(x49gp); + x49gp_s3c2410_nand_init(x49gp); + x49gp_s3c2410_uart_init(x49gp); + x49gp_s3c2410_timer_init(x49gp); + x49gp_s3c2410_usbdev_init(x49gp); + x49gp_s3c2410_watchdog_init(x49gp); + /* x49gp_s3c2410_i2c_init(x49gp); */ + /* x49gp_s3c2410_iis_init(x49gp); */ + x49gp_s3c2410_io_port_init(x49gp); + x49gp_s3c2410_rtc_init(x49gp); + x49gp_s3c2410_adc_init(x49gp); + x49gp_s3c2410_spi_init(x49gp); + x49gp_s3c2410_sdi_init(x49gp); + + return 0; +} + +int +s3c2410_exit(x49gp_t *x49gp) +{ + return 0; +} diff --git a/s3c2410_adc.c b/s3c2410_adc.c new file mode 100644 index 0000000..d540f19 --- /dev/null +++ b/s3c2410_adc.c @@ -0,0 +1,270 @@ +/* $Id: s3c2410_adc.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef struct { + uint32_t adccon; + uint32_t adctsc; + uint32_t adcdly; + uint32_t adcdat0; + uint32_t adcdat1; + + unsigned int nr_regs; + s3c2410_offset_t *regs; +} s3c2410_adc_t; + +static int +s3c2410_adc_data_init(s3c2410_adc_t *adc) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(ADC, ADCCON, 0x00003fc4, adc->adccon), + S3C2410_OFFSET(ADC, ADCTSC, 0x00000058, adc->adctsc), + S3C2410_OFFSET(ADC, ADCDLY, 0x000000ff, adc->adcdly), + S3C2410_OFFSET(ADC, ADCDAT0, 0x3ff, adc->adcdat0), + S3C2410_OFFSET(ADC, ADCDAT1, 0x3ff, adc->adcdat1), + }; + + memset(adc, 0, sizeof(s3c2410_adc_t)); + + adc->regs = malloc(sizeof(regs)); + if (NULL == adc->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(adc->regs, regs, sizeof(regs)); + adc->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static uint32_t +s3c2410_adc_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_adc_t *adc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_ADC_BASE; +#endif + if (! S3C2410_OFFSET_OK(adc, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(adc, offset); + +#ifdef DEBUG_S3C2410_ADC + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-adc", S3C2410_ADC_BASE, + reg->name, offset, *(reg->datap)); +#endif + + switch (offset) { + case S3C2410_ADC_ADCCON: + *(reg->datap) &= ~(0x0001); + *(reg->datap) |= 0x8000; + break; + default: + break; + } + + return *(reg->datap); +} + +static void +s3c2410_adc_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_adc_t *adc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_ADC_BASE; +#endif + if (! S3C2410_OFFSET_OK(adc, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(adc, offset); + +#ifdef DEBUG_S3C2410_ADC + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-adc", S3C2410_ADC_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; +} + +static int +s3c2410_adc_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_adc_t *adc = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < adc->nr_regs; i++) { + reg = &adc->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_adc_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_adc_t *adc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < adc->nr_regs; i++) { + reg = &adc->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_adc_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_adc_t *adc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < adc->nr_regs; i++) { + reg = &adc->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_adc_readfn[] = +{ + s3c2410_adc_read, + s3c2410_adc_read, + s3c2410_adc_read +}; + +static CPUWriteMemoryFunc *s3c2410_adc_writefn[] = +{ + s3c2410_adc_write, + s3c2410_adc_write, + s3c2410_adc_write +}; + +static int +s3c2410_adc_init(x49gp_module_t *module) +{ + s3c2410_adc_t *adc; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + adc = malloc(sizeof(s3c2410_adc_t)); + if (NULL == adc) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_adc_data_init(adc)) { + free(adc); + return -ENOMEM; + } + + module->user_data = adc; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_adc_readfn, + s3c2410_adc_writefn, adc); +#else + iotype = cpu_register_io_memory(s3c2410_adc_readfn, + s3c2410_adc_writefn, adc); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_ADC_BASE, S3C2410_MAP_SIZE, iotype); + + return 0; +} + +static int +s3c2410_adc_exit(x49gp_module_t *module) +{ + s3c2410_adc_t *adc; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + adc = module->user_data; + if (adc->regs) + free(adc->regs); + free(adc); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_adc_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-adc", + s3c2410_adc_init, + s3c2410_adc_exit, + s3c2410_adc_reset, + s3c2410_adc_load, + s3c2410_adc_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_arm.c b/s3c2410_arm.c new file mode 100644 index 0000000..82d8bc0 --- /dev/null +++ b/s3c2410_arm.c @@ -0,0 +1,288 @@ +/* $Id: s3c2410_arm.c,v 1.7 2008/12/11 12:18:17 ecd Exp $ + */ + + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef QEMU_OLD +extern void tlb_flush(struct CPUState *, int global); +#else +#include "cpu-all.h" +#endif + +static int +s3c2410_arm_load(x49gp_module_t *module, GKeyFile *key) +{ + struct CPUARMState *env = module->user_data; + char name[32]; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + cpu_reset(env); + tlb_flush(env, 1); + + for (i = 0; i < 16; i++) { + sprintf(name, "reg-%02u", i); + if (x49gp_module_get_u32(module, key, name, 0, &env->regs[i])) + error = -EAGAIN; + } + if (x49gp_module_get_u32(module, key, "cpsr", 0, &env->uncached_cpsr)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "spsr", 0, &env->spsr)) + error = -EAGAIN; + for (i = 0; i < 6; i++) { + sprintf(name, "banked-spsr-%02u", i); + if (x49gp_module_get_u32(module, key, name, 0, &env->banked_spsr[i])) + error = -EAGAIN; + sprintf(name, "banked-r13-%02u", i); + if (x49gp_module_get_u32(module, key, name, 0, &env->banked_r13[i])) + error = -EAGAIN; + sprintf(name, "banked-r14-%02u", i); + if (x49gp_module_get_u32(module, key, name, 0, &env->banked_r14[i])) + error = -EAGAIN; + } + for (i = 8; i < 12; i++) { + sprintf(name, "reg-usr-%02u", i); + if (x49gp_module_get_u32(module, key, name, + 0, &env->usr_regs[i])) + error = -EAGAIN; + sprintf(name, "reg-fiq-%02u", i); + if (x49gp_module_get_u32(module, key, name, + 0, &env->fiq_regs[i])) + error = -EAGAIN; + } + + if (x49gp_module_get_u32(module, key, "CF", 0, &env->CF)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "VF", 0, &env->VF)) + error = -EAGAIN; +#ifdef QEMU_OLD + if (x49gp_module_get_u32(module, key, "NZF", 0, &env->NZF)) + error = -EAGAIN; +#else + if (x49gp_module_get_u32(module, key, "NF", 0, &env->NF)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "ZF", 0, &env->ZF)) + error = -EAGAIN; +#endif + if (x49gp_module_get_u32(module, key, "QF", 0, &env->QF)) + error = -EAGAIN; + if (x49gp_module_get_int(module, key, "thumb", 0, &env->thumb)) + error = -EAGAIN; + + if (x49gp_module_get_u32(module, key, "cp15-c0-cpuid", 0, &env->cp15.c0_cpuid)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c1-sys", 0, &env->cp15.c1_sys)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c1-coproc", 0, &env->cp15.c1_coproc)) + error = -EAGAIN; +#ifdef QEMU_OLD + if (x49gp_module_get_u32(module, key, "cp15-c2", 0, &env->cp15.c2)) + error = -EAGAIN; +#else + if (x49gp_module_get_u32(module, key, "cp15-c2-base0", 0, &env->cp15.c2_base0)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-base1", 0, &env->cp15.c2_base1)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-control", 0, &env->cp15.c2_control)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-mask", 0, &env->cp15.c2_mask)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-base-mask", 0, &env->cp15.c2_base_mask)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-data", 0, &env->cp15.c2_data)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c2-insn", 0, &env->cp15.c2_insn)) + error = -EAGAIN; +#endif + if (x49gp_module_get_u32(module, key, "cp15-c3", 0, &env->cp15.c3)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c5-insn", 0, &env->cp15.c5_insn)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c5-data", 0, &env->cp15.c5_data)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c6-insn", 0, &env->cp15.c6_insn)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c6-data", 0, &env->cp15.c6_data)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c9-insn", 0, &env->cp15.c9_insn)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c9-data", 0, &env->cp15.c9_data)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c13-fcse", 0, &env->cp15.c13_fcse)) + error = -EAGAIN; + if (x49gp_module_get_u32(module, key, "cp15-c13-context", 0, &env->cp15.c13_context)) + error = -EAGAIN; + + if (x49gp_module_get_u32(module, key, "features", 0, &env->features)) + error = -EAGAIN; + + if (x49gp_module_get_int(module, key, "exception-index", 0, &env->exception_index)) + error = -EAGAIN; + if (x49gp_module_get_int(module, key, "interrupt-request", 0, &env->interrupt_request)) + error = -EAGAIN; + if (x49gp_module_get_int(module, key, "halted", 0, &env->halted)) + error = -EAGAIN; + + env->exception_index = -1; + + if (0 == error) { + if (env->halted) + module->x49gp->arm_idle = 1; + } else { + memset(&env->cp15, 0, sizeof(env->cp15)); + } + +// s3c2410_arm_dump_state(state); + + return error; +} + +static int +s3c2410_arm_save(x49gp_module_t *module, GKeyFile *key) +{ + struct CPUARMState *env = module->user_data; + char name[32]; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < 16; i++) { + sprintf(name, "reg-%02u", i); + x49gp_module_set_u32(module, key, name, env->regs[i]); + } + x49gp_module_set_u32(module, key, "cpsr", env->uncached_cpsr); + x49gp_module_set_u32(module, key, "spsr", env->spsr); + for (i = 0; i < 6; i++) { + sprintf(name, "banked-spsr-%02u", i); + x49gp_module_set_u32(module, key, name, env->banked_spsr[i]); + sprintf(name, "banked-r13-%02u", i); + x49gp_module_set_u32(module, key, name, env->banked_r13[i]); + sprintf(name, "banked-r14-%02u", i); + x49gp_module_set_u32(module, key, name, env->banked_r14[i]); + } + for (i = 8; i < 12; i++) { + sprintf(name, "reg-usr-%02u", i); + x49gp_module_set_u32(module, key, name, env->usr_regs[i]); + sprintf(name, "reg-fiq-%02u", i); + x49gp_module_set_u32(module, key, name, env->fiq_regs[i]); + } + + x49gp_module_set_u32(module, key, "CF", env->CF); + x49gp_module_set_u32(module, key, "VF", env->VF); +#ifdef QEMU_OLD + x49gp_module_set_u32(module, key, "NZF", env->NZF); +#else + x49gp_module_set_u32(module, key, "NF", env->NF); + x49gp_module_set_u32(module, key, "ZF", env->ZF); +#endif + x49gp_module_set_u32(module, key, "QF", env->QF); + x49gp_module_set_int(module, key, "thumb", env->thumb); + + x49gp_module_set_u32(module, key, "cp15-c0-cpuid", env->cp15.c0_cpuid); + x49gp_module_set_u32(module, key, "cp15-c1-sys", env->cp15.c1_sys); + x49gp_module_set_u32(module, key, "cp15-c1-coproc", env->cp15.c1_coproc); +#ifdef QEMU_OLD + x49gp_module_set_u32(module, key, "cp15-c2", env->cp15.c2); +#else + x49gp_module_set_u32(module, key, "cp15-c2-base0", env->cp15.c2_base0); + x49gp_module_set_u32(module, key, "cp15-c2-base1", env->cp15.c2_base1); + x49gp_module_set_u32(module, key, "cp15-c2-control", env->cp15.c2_control); + x49gp_module_set_u32(module, key, "cp15-c2-mask", env->cp15.c2_mask); + x49gp_module_set_u32(module, key, "cp15-c2-base-mask", env->cp15.c2_base_mask); + x49gp_module_set_u32(module, key, "cp15-c2-data", env->cp15.c2_data); + x49gp_module_set_u32(module, key, "cp15-c2-insn", env->cp15.c2_insn); +#endif + x49gp_module_set_u32(module, key, "cp15-c3", env->cp15.c3); + x49gp_module_set_u32(module, key, "cp15-c5-insn", env->cp15.c5_insn); + x49gp_module_set_u32(module, key, "cp15-c5-data", env->cp15.c5_data); + x49gp_module_set_u32(module, key, "cp15-c6-insn", env->cp15.c6_insn); + x49gp_module_set_u32(module, key, "cp15-c6-data", env->cp15.c6_data); + x49gp_module_set_u32(module, key, "cp15-c9-insn", env->cp15.c9_insn); + x49gp_module_set_u32(module, key, "cp15-c9-data", env->cp15.c9_data); + x49gp_module_set_u32(module, key, "cp15-c13-fcse", env->cp15.c13_fcse); + x49gp_module_set_u32(module, key, "cp15-c13-context", env->cp15.c13_context); + + x49gp_module_set_u32(module, key, "features", env->features); + + x49gp_module_set_int(module, key, "exception-index", env->exception_index); + x49gp_module_set_int(module, key, "interrupt-request", env->interrupt_request); + x49gp_module_set_int(module, key, "halted", env->halted); + + return 0; +} + +static int +s3c2410_arm_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + struct CPUARMState *env = module->user_data; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + cpu_reset(env); + tlb_flush(env, 1); + + return 0; +} + +static int +s3c2410_arm_init(x49gp_module_t *module) +{ + x49gp_t *x49gp = module->x49gp; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + +#ifdef QEMU_OLD + cpu_arm_set_model(x49gp->env, ARM_CPUID_ARM926); +#endif + + module->user_data = x49gp->env; + return 0; +} + +static int +s3c2410_arm_exit(x49gp_module_t *module) +{ +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + return 0; +} + +int +x49gp_s3c2410_arm_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-arm", + s3c2410_arm_init, + s3c2410_arm_exit, + s3c2410_arm_reset, + s3c2410_arm_load, + s3c2410_arm_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_intc.c b/s3c2410_intc.c new file mode 100644 index 0000000..211c97a --- /dev/null +++ b/s3c2410_intc.c @@ -0,0 +1,751 @@ +/* $Id: s3c2410_intc.c,v 1.8 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int do_trace; + +typedef struct { + int sel_shift; + uint32_t mode_bit; + int index; + int req[6]; +} s3c2410_arb_t; + +typedef struct { + uint32_t sel; + uint32_t mode; +} s3c2410_arb_data_t; + +static const int s3c2410_arb_order[4][6] = +{ + { 0, 1, 2, 3, 4, 5 }, + { 0, 2, 3, 4, 1, 5 }, + { 0, 3, 4, 1, 2, 5 }, + { 0, 4, 1, 2, 3, 5 } +}; + +static const s3c2410_arb_t s3c2410_arb_table[] = +{ + [0] = { ARB0_SEL_SHIFT, ARB0_MODE, 0, + { -1, EINT0, EINT1, EINT2, EINT3, -1 } }, + [1] = { ARB1_SEL_SHIFT, ARB1_MODE, 1, + { EINT4_7, EINT8_23, -1, nBATT_FLT, INT_TICK, INT_WDT } }, + [2] = { ARB2_SEL_SHIFT, ARB2_MODE, 2, + { INT_TIMER0, INT_TIMER1, INT_TIMER2, INT_TIMER3, INT_TIMER4, INT_UART2} }, + [3] = { ARB3_SEL_SHIFT, ARB3_MODE, 3, + { INT_LCD, INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3, INT_SDI } }, + [4] = { ARB4_SEL_SHIFT, ARB4_MODE, 4, + { INT_SPI0, INT_UART1, -1, INT_USBD, INT_USBH, INT_IIC } }, + [5] = { ARB5_SEL_SHIFT, ARB5_MODE, 5, + { -1, INT_UART0, INT_SPI1, INT_RTC, INT_ADC, -1, } }, + [6] = { ARB6_SEL_SHIFT, ARB6_MODE, 6, + { 0, 1, 2, 3, 4, 5 } }, +}; +#define INTC_NR_ARB (sizeof(s3c2410_arb_table) / sizeof(s3c2410_arb_table[0])) + + +typedef struct { + uint32_t srcpnd; + uint32_t intmod; + uint32_t intmsk; + uint32_t priority; + uint32_t intpnd; + uint32_t intoffset; + uint32_t subsrcpnd; + uint32_t intsubmsk; + + s3c2410_arb_data_t arb_data[INTC_NR_ARB]; + + x49gp_t *x49gp; + + uint32_t src_pending; + uint32_t subsrc_pending; + + unsigned int nr_regs; + s3c2410_offset_t *regs; +} s3c2410_intc_t; + + +static void s3c2410_intc_gen_int(s3c2410_intc_t *intc); +static void s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc); + +static int +s3c2410_intc_data_init(s3c2410_intc_t *intc) +{ + int i; + + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(INTC, SRCPND, 0x00000000, intc->srcpnd), + S3C2410_OFFSET(INTC, INTMOD, 0x00000000, intc->intmod), + S3C2410_OFFSET(INTC, INTMSK, 0xffffffff, intc->intmsk), + S3C2410_OFFSET(INTC, PRIORITY, 0x0000007f, intc->priority), + S3C2410_OFFSET(INTC, INTPND, 0x00000000, intc->intpnd), + S3C2410_OFFSET(INTC, INTOFFSET, 0x00000000, intc->intoffset), + S3C2410_OFFSET(INTC, SUBSRCPND, 0x00000000, intc->subsrcpnd), + S3C2410_OFFSET(INTC, INTSUBMSK, 0x000007ff, intc->intsubmsk) + }; + + memset(intc, 0, sizeof(s3c2410_intc_t)); + + intc->regs = malloc(sizeof(regs)); + if (NULL == intc->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(intc->regs, regs, sizeof(regs)); + intc->nr_regs = sizeof(regs) / sizeof(regs[0]); + + for (i = 0; i < INTC_NR_ARB; i++) { + intc->arb_data[i].sel = 0; + intc->arb_data[i].mode = s3c2410_arb_table[i].mode_bit; + } + + return 0; +} + +static void +srcpnd_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + intc->srcpnd &= ~(data); + intc->srcpnd |= intc->src_pending; + + if (intc->src_pending & data) { + s3c2410_intc_gen_int(intc); + } +} + +static void +intmod_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + intc->intmod = data & 0xfeffffbf; + + s3c2410_intc_gen_int(intc); +} + +static void +intmsk_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + uint32_t change; +#ifdef DEBUG_X49GP_ENABLE_IRQ + int i; +#endif + + change = intc->intmsk ^ data; + + intc->intmsk = data | 0x01000040; + +#ifdef DEBUG_X49GP_ENABLE_IRQ + for (i = 0; i < 32; i++) { + if ((change & (1 << i)) && !(intc->intmsk & (1 << i))) { + printf("INTC: Enable IRQ %u\n", i); + } + } +#endif + + s3c2410_intc_gen_int(intc); +} + +static uint32_t +priority_get_word(s3c2410_intc_t *intc) +{ + const s3c2410_arb_t *arb; + s3c2410_arb_data_t *arb_data; + int i; + + intc->priority = 0; + + for (i = 0; i < INTC_NR_ARB; i++) { + arb = &s3c2410_arb_table[i]; + arb_data = &intc->arb_data[i]; + + intc->priority |= (arb_data->sel << arb->sel_shift) | + arb_data->mode; + } + + return intc->priority; +} + +static void +priority_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + const s3c2410_arb_t *arb; + s3c2410_arb_data_t *arb_data; + int i; + + intc->priority = data & 0x001fffff; + + for (i = 0; i < INTC_NR_ARB; i++) { + arb = &s3c2410_arb_table[i]; + arb_data = &intc->arb_data[i]; + + arb_data->sel = (intc->priority >> arb->sel_shift) & ARBx_SEL_MASK; + arb_data->mode = intc->priority & arb->mode_bit; + } + + s3c2410_intc_gen_int(intc); +} + +static void +intpnd_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + intc->intpnd &= ~(data); + + s3c2410_intc_gen_int(intc); +} + +static void +subsrcpnd_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + intc->subsrcpnd &= ~(data); + intc->subsrcpnd |= intc->subsrc_pending; + + if (intc->subsrc_pending & data) { + s3c2410_intc_gen_int_from_sub_int(intc); + } +} + +static void +intsubmsk_put_word(s3c2410_intc_t *intc, uint32_t data) +{ + intc->intsubmsk = data & 0x000007ff; + + s3c2410_intc_gen_int_from_sub_int(intc); +} + +static uint32_t +s3c2410_intc_select_int(s3c2410_intc_t *intc, const s3c2410_arb_t *arb, + uint32_t service, int *offset) +{ + s3c2410_arb_data_t *arb_data = &intc->arb_data[arb->index]; + const int *order; + int i, req; + + order = s3c2410_arb_order[arb_data->sel]; + + for (i = 0; i < 6; i++) { + req = order[i]; + + if (-1 == arb->req[req]) + continue; + + if (service & (1 << arb->req[req])) { + if (arb_data->mode) + arb_data->sel = (arb_data->sel + 1) & ARBx_SEL_MASK; + *offset = arb->req[req]; + return (1 << arb->index); + } + } + + *offset = -1; + return 0; +} + +void +s3c2410_FIQ (CPUState *env) +{ + cpu_interrupt(env, CPU_INTERRUPT_FIQ); +} + +void +s3c2410_IRQ (CPUState *env) +{ + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + + +static void +s3c2410_intc_gen_int(s3c2410_intc_t *intc) +{ + x49gp_t *x49gp = intc->x49gp; + uint32_t fiq, service; + int offset[6], index; + const s3c2410_arb_t *arb; + uint32_t request; + int i; + + fiq = intc->srcpnd & intc->intmod; + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: FIQ service request: %08x\n", fiq); +#endif + + if (fiq) { + /* + * Generate FIQ. + */ +#ifdef DEBUG_S3C2410_INTC + printf("INTC: vector to %08x\n", 0x1c); +#endif + cpu_interrupt(x49gp->env, CPU_INTERRUPT_FIQ); + + x49gp_set_idle(x49gp, 0); + return; + } else { + cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_FIQ); + } + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: IRQ pending request: %08x\n", intc->intpnd); +#endif + + if (intc->intpnd) { + /* + * Generate IRQ. + */ +#ifdef DEBUG_S3C2410_INTC + printf("INTC: vector to %08x\n", 0x18); +#endif + cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD); + + x49gp_set_idle(x49gp, 0); + return; + } + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: srcpnd %08x, intmsk: %08x\n", intc->srcpnd, intc->intmsk); +#endif + + service = intc->srcpnd & ~(intc->intmsk); + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: IRQ service request: %08x\n", service); +#endif + + if (0 == service) { + cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD); + return; + } + + request = 0; + for (i = 0; i < 6; i++) { + arb = &s3c2410_arb_table[i]; + + request |= s3c2410_intc_select_int(intc, arb, service, &offset[i]); + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: ARB%u highest %d\n", i, offset[i]); +#endif + } + + arb = &s3c2410_arb_table[6]; + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: ARB%u request: %08x\n", 6, request); +#endif + + if (s3c2410_intc_select_int(intc, arb, request, &index)) { + intc->intoffset = offset[index]; + intc->intpnd |= (1 << intc->intoffset); + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: irq pending: %u (%08x)\n", intc->intoffset, intc->intpnd); +#endif + /* + * Generate IRQ. + */ +#ifdef DEBUG_S3C2410_INTC + printf("INTC: vector to %08x\n", 0x18); +#endif + cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD); + + x49gp_set_idle(x49gp, 0); + return; + } + +#ifdef DEBUG_S3C2410_INTC0 + printf("INTC: No irq pending\n"); +#endif + + cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD); +} + +void +s3c2410_intc_assert(x49gp_t *x49gp, int irq, int level) +{ + s3c2410_intc_t *intc = x49gp->s3c2410_intc; + + if (irq > 31) + return; + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: assert irq %u (%08x)\n", irq, 1 << irq); +#endif + + if (! (intc->src_pending & (1 << irq))) { + if (level) + intc->src_pending |= (1 << irq); + intc->srcpnd |= (1 << irq); + + s3c2410_intc_gen_int(intc); + } + + if (x49gp->arm_idle == 2) { + if (irq == EINT0 || irq == INT_RTC) + x49gp_set_idle(x49gp, 0); + } +} + +void +s3c2410_intc_deassert(x49gp_t *x49gp, int irq) +{ + s3c2410_intc_t *intc = x49gp->s3c2410_intc; + + if (irq > 31) + return; + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: deassert irq %u (%08x)\n", irq, 1 << irq); +#endif + + intc->src_pending &= ~(1 << irq); +} + +static void +s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc) +{ + x49gp_t *x49gp = intc->x49gp; + uint32_t service; + + service = intc->subsrcpnd & ~(intc->intsubmsk); + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: subirq service request: %08x\n", service); +#endif + + if (service & ((1 << SUB_INT_ERR0) | (1 << SUB_INT_TXD0) | (1 << SUB_INT_RXD0))) { + s3c2410_intc_assert(x49gp, INT_UART0, 1); + } else { + s3c2410_intc_deassert(x49gp, INT_UART0); + } + + if (service & ((1 << SUB_INT_ERR1) | (1 << SUB_INT_TXD1) | (1 << SUB_INT_RXD1))) { + s3c2410_intc_assert(x49gp, INT_UART1, 1); + } else { + s3c2410_intc_deassert(x49gp, INT_UART1); + } + + if (service & ((1 << SUB_INT_ERR2) | (1 << SUB_INT_TXD2) | (1 << SUB_INT_RXD2))) { + s3c2410_intc_assert(x49gp, INT_UART2, 1); + } else { + s3c2410_intc_deassert(x49gp, INT_UART2); + } + + if (service & ((1 << SUB_INT_ADC) | (1 << SUB_INT_TC))) { + s3c2410_intc_assert(x49gp, INT_ADC, 1); + } else { + s3c2410_intc_deassert(x49gp, INT_ADC); + } + + intc->subsrcpnd = intc->subsrc_pending; +} + +void +s3c2410_intc_sub_assert(x49gp_t *x49gp, int sub_irq, int level) +{ + s3c2410_intc_t *intc = x49gp->s3c2410_intc; + + if (sub_irq > 31) + return; + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: assert subirq %u (%08x)\n", sub_irq, 1 << sub_irq); +#endif + + if (! (intc->subsrc_pending & (1 << sub_irq))) { + if (level) + intc->subsrc_pending |= (1 << sub_irq); + intc->subsrcpnd |= (1 << sub_irq); + + s3c2410_intc_gen_int_from_sub_int(intc); + } +} + +void +s3c2410_intc_sub_deassert(x49gp_t *x49gp, int sub_irq) +{ + s3c2410_intc_t *intc = x49gp->s3c2410_intc; + + if (sub_irq > 31) + return; + +#ifdef DEBUG_S3C2410_INTC + printf("INTC: deassert subirq %u (%08x)\n", sub_irq, 1 << sub_irq); +#endif + + intc->subsrc_pending &= ~(1 << sub_irq); +} + +static uint32_t +s3c2410_intc_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_intc_t *intc = opaque; + s3c2410_offset_t *reg; + uint32_t data; + +#ifdef QEMU_OLD + offset -= S3C2410_INTC_BASE; +#endif + if (! S3C2410_OFFSET_OK(intc, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(intc, offset); + + switch (offset) { + case S3C2410_INTC_PRIORITY: + data = priority_get_word(intc); + break; + default: + data = *(reg->datap); + break; + } + +#ifdef DEBUG_S3C2410_INTC + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-intc", S3C2410_INTC_BASE, + reg->name, offset, data); +#endif + + return data; +} + +static void +s3c2410_intc_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_intc_t *intc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_INTC_BASE; +#endif + if (! S3C2410_OFFSET_OK(intc, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(intc, offset); + +#ifdef DEBUG_S3C2410_INTC + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-intc", S3C2410_INTC_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_INTC_SRCPND: + srcpnd_put_word(intc, data); + break; + case S3C2410_INTC_INTMOD: + intmod_put_word(intc, data); + break; + case S3C2410_INTC_INTMSK: + intmsk_put_word(intc, data); + break; + case S3C2410_INTC_PRIORITY: + priority_put_word(intc, data); + break; + case S3C2410_INTC_INTPND: + intpnd_put_word(intc, data); + break; + case S3C2410_INTC_SUBSRCPND: + subsrcpnd_put_word(intc, data); + break; + case S3C2410_INTC_INTSUBMSK: + intsubmsk_put_word(intc, data); + break; + default: + break; + } +} + +static int +s3c2410_intc_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_intc_t *intc = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < intc->nr_regs; i++) { + reg = &intc->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + intc->src_pending = intc->srcpnd; + intc->subsrc_pending = intc->subsrcpnd; + intc->srcpnd = 0; + intc->subsrcpnd = 0; + + priority_put_word(intc, intc->priority); + intsubmsk_put_word(intc, intc->intsubmsk); + intmsk_put_word(intc, intc->intmsk); + + return error; +} + +static int +s3c2410_intc_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_intc_t *intc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + intc->srcpnd = intc->src_pending; + intc->subsrcpnd = intc->subsrc_pending; + + for (i = 0; i < intc->nr_regs; i++) { + reg = &intc->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_intc_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_intc_t *intc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (reset == X49GP_RESET_POWER_OFF) { + return 0; + } + + for (i = 0; i < intc->nr_regs; i++) { + reg = &intc->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_intc_readfn[] = +{ + s3c2410_intc_read, + s3c2410_intc_read, + s3c2410_intc_read +}; + +static CPUWriteMemoryFunc *s3c2410_intc_writefn[] = +{ + s3c2410_intc_write, + s3c2410_intc_write, + s3c2410_intc_write +}; + +static int +s3c2410_intc_init(x49gp_module_t *module) +{ + s3c2410_intc_t *intc; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + intc = malloc(sizeof(s3c2410_intc_t)); + if (NULL == intc) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_intc_data_init(intc)) { + free(intc); + return -ENOMEM; + } + + module->user_data = intc; + + intc->x49gp = module->x49gp; + intc->x49gp->s3c2410_intc = intc; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_intc_readfn, + s3c2410_intc_writefn, intc); +#else + iotype = cpu_register_io_memory(s3c2410_intc_readfn, + s3c2410_intc_writefn, intc); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_INTC_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_intc_exit(x49gp_module_t *module) +{ + s3c2410_intc_t *intc; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + intc = module->user_data; + if (intc->regs) + free(intc->regs); + free(intc); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_intc_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-intc", + s3c2410_intc_init, + s3c2410_intc_exit, + s3c2410_intc_reset, + s3c2410_intc_load, + s3c2410_intc_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_io_port.c b/s3c2410_io_port.c new file mode 100644 index 0000000..8aac85d --- /dev/null +++ b/s3c2410_io_port.c @@ -0,0 +1,727 @@ +/* $Id: s3c2410_io_port.c,v 1.14 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +typedef struct { + uint32_t gpacon; + uint32_t gpadat; + + uint32_t gpbcon; + uint32_t gpbdat; + uint32_t gpbup; + + uint32_t gpccon; + uint32_t gpcdat; + uint32_t gpcup; + + uint32_t gpdcon; + uint32_t gpddat; + uint32_t gpdup; + + uint32_t gpecon; + uint32_t gpedat; + uint32_t gpeup; + + uint32_t gpfcon; + uint32_t gpfdat; + uint32_t gpfup; + + uint32_t gpgcon; + uint32_t gpgdat; + uint32_t gpgup; + + uint32_t gphcon; + uint32_t gphdat; + uint32_t gphup; + + uint32_t misccr; + uint32_t dclkcon; + + uint32_t extint0; + uint32_t extint1; + uint32_t extint2; + uint32_t eintflt0; + uint32_t eintflt1; + uint32_t eintflt2; + uint32_t eintflt3; + uint32_t eintmask; + uint32_t eintpend; + + uint32_t gstatus0; + uint32_t gstatus1; + uint32_t gstatus2; + uint32_t gstatus3; + uint32_t gstatus4; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_io_port_t; + +static int +s3c2410_io_port_data_init(s3c2410_io_port_t *io) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(IO_PORT, GPACON, 0x007fffff, io->gpacon), + S3C2410_OFFSET(IO_PORT, GPADAT, 0x00000000, io->gpadat), + + S3C2410_OFFSET(IO_PORT, GPBCON, 0x00000000, io->gpbcon), + S3C2410_OFFSET(IO_PORT, GPBDAT, 0x00000000, io->gpbdat), + S3C2410_OFFSET(IO_PORT, GPBUP, 0x00000000, io->gpbup), + + S3C2410_OFFSET(IO_PORT, GPCCON, 0x00000000, io->gpccon), + S3C2410_OFFSET(IO_PORT, GPCDAT, 0x00000000, io->gpcdat), + S3C2410_OFFSET(IO_PORT, GPCUP, 0x00000000, io->gpcup), + + S3C2410_OFFSET(IO_PORT, GPDCON, 0x00000000, io->gpdcon), + S3C2410_OFFSET(IO_PORT, GPDDAT, 0x0000038c, io->gpddat), + S3C2410_OFFSET(IO_PORT, GPDUP, 0x0000f000, io->gpdup), + + S3C2410_OFFSET(IO_PORT, GPECON, 0x00000000, io->gpecon), + S3C2410_OFFSET(IO_PORT, GPEDAT, 0x0000c7c0, io->gpedat), + S3C2410_OFFSET(IO_PORT, GPEUP, 0x00000000, io->gpeup), + + S3C2410_OFFSET(IO_PORT, GPFCON, 0x00000000, io->gpfcon), + S3C2410_OFFSET(IO_PORT, GPFDAT, 0x00000008, io->gpfdat), + S3C2410_OFFSET(IO_PORT, GPFUP, 0x00000000, io->gpfup), + + S3C2410_OFFSET(IO_PORT, GPGCON, 0x00000000, io->gpgcon), + S3C2410_OFFSET(IO_PORT, GPGDAT, 0x0000fffe, io->gpgdat), + S3C2410_OFFSET(IO_PORT, GPGUP, 0x0000f800, io->gpgup), + + S3C2410_OFFSET(IO_PORT, GPHCON, 0x00000000, io->gphcon), + S3C2410_OFFSET(IO_PORT, GPHDAT, 0x00000000, io->gphdat), + S3C2410_OFFSET(IO_PORT, GPHUP, 0x00000000, io->gphup), + + S3C2410_OFFSET(IO_PORT, MISCCR, 0x00010330, io->misccr), + S3C2410_OFFSET(IO_PORT, DCLKCON, 0x00000000, io->dclkcon), + + S3C2410_OFFSET(IO_PORT, EXTINT0, 0x00000000, io->extint0), + S3C2410_OFFSET(IO_PORT, EXTINT1, 0x00000000, io->extint1), + S3C2410_OFFSET(IO_PORT, EXTINT2, 0x00000000, io->extint2), + S3C2410_OFFSET(IO_PORT, EINTFLT0, 0x00000000, io->eintflt0), + S3C2410_OFFSET(IO_PORT, EINTFLT1, 0x00000000, io->eintflt1), + S3C2410_OFFSET(IO_PORT, EINTFLT2, 0x00000000, io->eintflt2), + S3C2410_OFFSET(IO_PORT, EINTFLT3, 0x00000000, io->eintflt3), + S3C2410_OFFSET(IO_PORT, EINTMASK, 0x00fffff0, io->eintmask), + S3C2410_OFFSET(IO_PORT, EINTPEND, 0x00000000, io->eintpend), + + S3C2410_OFFSET(IO_PORT, GSTATUS0, 0x00000001, io->gstatus0), + S3C2410_OFFSET(IO_PORT, GSTATUS1, 0x32410002, io->gstatus1), + S3C2410_OFFSET(IO_PORT, GSTATUS2, 0x00000001, io->gstatus2), + S3C2410_OFFSET(IO_PORT, GSTATUS3, 0x00000000, io->gstatus3), + S3C2410_OFFSET(IO_PORT, GSTATUS4, 0x00000000, io->gstatus4) + }; + + memset(io, 0, sizeof(s3c2410_io_port_t)); + + io->regs = malloc(sizeof(regs)); + if (NULL == io->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(io->regs, regs, sizeof(regs)); + io->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static uint32_t +s3c2410_scan_keys(x49gp_t *x49gp, uint32_t gpgcon, uint32_t gpgdat) +{ + uint32_t result; + int col, row; + + result = 0xfffe | (gpgdat & 1); + + for (col = 0; col < 8; col++) { + switch ((gpgcon >> (2 * (col + 8))) & 3) { + case 0: /* Input */ + case 2: /* Interrupt */ + case 3: /* Reserved */ + break; + case 1: /* Output */ + result &= ~(1 << (col + 8)); + result |= gpgdat & (1 << (col + 8)); + + if (0 == (gpgdat & (1 << (col + 8)))) { + result &= ~(x49gp->keybycol[col]); + } + break; + } + } + + for (row = 1; row < 8; row++) { + switch ((gpgcon >> (2 * row)) & 3) { + case 0: /* Input */ + case 2: /* Interrupt */ + case 3: /* Reserved */ + break; + case 1: /* Output */ + result &= ~(1 << row); + result |= gpgdat & (1 << row); + + if (0 == (gpgdat & (1 << row))) { + result &= ~(x49gp->keybyrow[row] << 8); + } + break; + } + } + + return result; +} + +static uint32_t +s3c2410_io_port_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_io_port_t *io = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_IO_PORT_BASE; +#endif + if (! S3C2410_OFFSET_OK(io, offset)) { +fprintf(stderr, "%s:%u: offset %08x not OK\n", __FUNCTION__, __LINE__, offset); +abort(); + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(io, offset); + + switch (offset) { + case S3C2410_IO_PORT_MISCCR: +// if (io->x49gp->arm->NresetSig != LOW) { + *(reg->datap) |= 0x00010000; +// } + break; + + case S3C2410_IO_PORT_GPCDAT: + if (0 == ((io->gpccon >> 30) & 3)) { + *(reg->datap) |= 0x8000; + } + if (0 == ((io->gpccon >> 28) & 3)) { + *(reg->datap) |= 0x4000; + } + if (0 == ((io->gpccon >> 26) & 3)) { + *(reg->datap) |= 0x2000; + } + if (0 == ((io->gpccon >> 24) & 3)) { + *(reg->datap) |= 0x1000; + } + break; + + case S3C2410_IO_PORT_GPDDAT: + if (0 == ((io->gpdcon >> 6) & 3)) { + *(reg->datap) |= 0x0008; + } + break; + + case S3C2410_IO_PORT_GPEDAT: + if (0 == ((io->gpecon >> 30) & 3)) { + *(reg->datap) |= 0x8000; + } + if (0 == ((io->gpecon >> 28) & 3)) { + *(reg->datap) |= 0x4000; + } + break; + + case S3C2410_IO_PORT_GPFDAT: +#if 1 + if (1 != ((io->gpfcon >> 6) & 3)) { + *(reg->datap) |= 0x0008; + } +#endif + break; + + case S3C2410_IO_PORT_GPGDAT: + *(reg->datap) = s3c2410_scan_keys(io->x49gp, io->gpgcon, *(reg->datap)); + break; + + case S3C2410_IO_PORT_GPHDAT: + if (0 == ((io->gphcon >> 14) & 3)) { + *(reg->datap) |= 0x80; + } + if (0 == ((io->gphcon >> 12) & 3)) { + *(reg->datap) &= ~(0x40); + } + break; + } + +#ifdef DEBUG_S3C2410_IO_PORT + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-io-port", S3C2410_IO_PORT_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_io_port_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_io_port_t *io = opaque; + s3c2410_offset_t *reg; + uint32_t change; +static uint32_t lcd_data = 0; + +#ifdef QEMU_OLD + offset -= S3C2410_IO_PORT_BASE; +#endif + if (! S3C2410_OFFSET_OK(io, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(io, offset); + +#ifdef DEBUG_S3C2410_IO_PORT + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-io-port", S3C2410_IO_PORT_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_IO_PORT_GPDDAT: + change = *(reg->datap) ^ data; + *(reg->datap) = data; + + if (!(data & 0x200) && (change & 0x200)) { + lcd_data = 0; + } + + if (!(data & 0x200) && (data & 0x2000) && (change & 0x2000)) { +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT GPDDAT: clk0 rise: data %u\n", + (data >> 12) & 1); +#endif + lcd_data <<= 1; + lcd_data |= (data >> 12) & 1; + } + + if ((data & 0x200) && (change & 0x200)) { +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT GPDDAT: cs0 rise: data %04x\n", + lcd_data); +#endif + } + + break; + + case S3C2410_IO_PORT_MISCCR: + *(reg->datap) = data; + if (!(*(reg->datap) & 0x00010000)) { + *(reg->datap) = 0x10330; +// if (io->x49gp->arm->NresetSig != LOW) { +// io->x49gp->arm->NresetSig = LOW; +// io->x49gp->arm->Exception++; +// } + } + break; + + case S3C2410_IO_PORT_GSTATUS0: + case S3C2410_IO_PORT_GSTATUS1: + /* read only */ + break; + + case S3C2410_IO_PORT_GSTATUS2: + *(reg->datap) &= ~(data & 7); + break; + + case S3C2410_IO_PORT_EINTPEND: + *(reg->datap) &= ~(data); + + if (0 == (*(reg->datap) & 0x000000f0)) + s3c2410_intc_deassert(io->x49gp, EINT4_7); + if (0 == (*(reg->datap) & 0x00ffff00)) + s3c2410_intc_deassert(io->x49gp, EINT8_23); + break; + + default: + *(reg->datap) = data; + break; + } +} + +void +s3c2410_io_port_g_set_bit(x49gp_t *x49gp, int n, uint32_t set) +{ + s3c2410_io_port_t *io = x49gp->s3c2410_io_port; + uint32_t value, change; + int pending, level; + + if (n > 7) + return; + +// g_mutex_lock(x49gp->memlock); + + io->gpgdat = s3c2410_scan_keys(x49gp, io->gpgcon, io->gpgdat); + +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT: %s GPG bit %u\n", set ? "assert" : "deassert", n); + printf("IO_PORT: GPGCON %08x, GPGDAT %08x\n", io->gpgcon, io->gpgdat); +#endif + + if (0 == set) { + value = 1; + } else { + if ((((io->gpgcon >> (2 * (n + 8))) & 3) == 1) && + (((io->gpgdat >> (n + 8)) & 1) == 0)) { + value = 0; + } else { + value = 1; + } + } + +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT: GPG bit %u value: %u\n", n, value); +#endif + + change = 0; + switch ((io->gpgcon >> (2 * n)) & 3) { + case 0: /* Input */ + io->gpgdat &= ~(1 << n); + io->gpgdat |= (value << n); + goto out; + + case 2: /* Interrupt */ + change = io->gpgdat ^ (value << n); + io->gpgdat &= ~(1 << n); + io->gpgdat |= (value << n); + break; + + case 1: /* Output */ + case 3: /* Reserved */ + goto out; + } + +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT: GPGDAT %08x, change %08x\n", io->gpgdat, change); +#endif + + pending = -1; + level = 0; + switch ((io->extint1 >> (4 * n)) & 7) { + case 0: /* Low Level */ + if (!(io->gpgdat & (1 << n))) + pending = n; + level = 1; + break; + case 1: /* High Level */ + if (io->gpgdat & (1 << n)) + pending = n; + level = 1; + break; + case 2: /* Falling Edge */ + case 3: + if ((change & (1 << n)) && !(io->gpgdat & (1 << n))) + pending = n; + break; + case 4: /* Rising Edge */ + case 5: + if ((change & (1 << n)) && (io->gpgdat & (1 << n))) + pending = n; + break; + case 6: /* Any Edge */ + case 7: + if (change & (1 << n)) + pending = n; + break; + } + +#ifdef DEBUG_S3C2410_IO_PORT + printf("IO_PORT: IRQ: %d, (Level %u)\n", pending, level); +#endif + + if (-1 == pending) + goto out; + + io->eintpend |= 1 << (n + 8); + if (io->eintpend & ~(io->eintmask)) + s3c2410_intc_assert(x49gp, EINT8_23, 1); + +out: +// g_mutex_unlock(x49gp->memlock); + + return; +} + +void +s3c2410_io_port_f_set_bit(x49gp_t *x49gp, int n, uint32_t value) +{ + s3c2410_io_port_t *io = x49gp->s3c2410_io_port; + uint32_t change; + int pending, level; + + if (n > 7) + return; + +// g_mutex_lock(x49gp->memlock); + + change = 0; + switch ((io->gpfcon >> (2 * n)) & 3) { + case 0: /* Input */ + io->gpfdat &= ~(1 << n); + io->gpfdat |= (value << n); + goto out; + + case 2: /* Interrupt */ + change = io->gpfdat ^ (value << n); + io->gpfdat &= ~(1 << n); + io->gpfdat |= (value << n); + break; + + case 1: /* Output */ + case 3: /* Reserved */ + goto out; + } + + pending = -1; + level = 0; + switch ((io->extint0 >> (4 * n)) & 7) { + case 0: /* Low Level */ + if (!(io->gpfdat & (1 << n))) + pending = n; + level = 1; + break; + + case 1: /* High Level */ + if (io->gpfdat & (1 << n)) + pending = n; + level = 1; + break; + + case 2: /* Falling Edge */ + case 3: + if ((change & (1 << n)) && !(io->gpfdat & (1 << n))) + pending = n; + break; + + case 4: /* Rising Edge */ + case 5: + if ((change & (1 << n)) && (io->gpfdat & (1 << n))) + pending = n; + break; + + case 6: /* Any Edge */ + case 7: + if (change & (1 << n)) + pending = n; + break; + } + + if (-1 == pending) + goto out; + + switch (n) { + case 0: + s3c2410_intc_assert(x49gp, EINT0, level); + break; + case 1: + s3c2410_intc_assert(x49gp, EINT1, level); + break; + case 2: + s3c2410_intc_assert(x49gp, EINT2, level); + break; + case 3: + s3c2410_intc_assert(x49gp, EINT3, level); + break; + case 4: + case 5: + case 6: + case 7: + io->eintpend |= (1 << n); + if (io->eintpend & ~(io->eintmask)) + s3c2410_intc_assert(x49gp, EINT4_7, 1); + break; + } + +out: +// g_mutex_unlock(x49gp->memlock); + + return; +} + +static int +s3c2410_io_port_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_io_port_t *io = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < io->nr_regs; i++) { + reg = &io->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_io_port_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_io_port_t *io = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < io->nr_regs; i++) { + reg = &io->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_io_port_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_io_port_t *io = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (reset == X49GP_RESET_POWER_OFF) { + io->gstatus2 = 2; + return 0; + } + + for (i = 0; i < io->nr_regs; i++) { + reg = &io->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + if (reset == X49GP_RESET_WATCHDOG) { + io->gstatus2 = 4; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_io_port_readfn[] = +{ + s3c2410_io_port_read, + s3c2410_io_port_read, + s3c2410_io_port_read +}; + +static CPUWriteMemoryFunc *s3c2410_io_port_writefn[] = +{ + s3c2410_io_port_write, + s3c2410_io_port_write, + s3c2410_io_port_write +}; + +static int +s3c2410_io_port_init(x49gp_module_t *module) +{ + s3c2410_io_port_t *io; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + io = malloc(sizeof(s3c2410_io_port_t)); + if (NULL == io) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_io_port_data_init(io)) { + free(io); + return -ENOMEM; + } + + module->user_data = io; + module->x49gp->s3c2410_io_port = io; + io->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_io_port_readfn, + s3c2410_io_port_writefn, io); +#else + iotype = cpu_register_io_memory(s3c2410_io_port_readfn, + s3c2410_io_port_writefn, io); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_IO_PORT_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_io_port_exit(x49gp_module_t *module) +{ + s3c2410_io_port_t *io; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + io = module->user_data; + if (io->regs) + free(io->regs); + free(io); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_io_port_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-io-port", + s3c2410_io_port_init, + s3c2410_io_port_exit, + s3c2410_io_port_reset, + s3c2410_io_port_load, + s3c2410_io_port_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_lcd.c b/s3c2410_lcd.c new file mode 100644 index 0000000..3753851 --- /dev/null +++ b/s3c2410_lcd.c @@ -0,0 +1,425 @@ +/* $Id: s3c2410_lcd.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +typedef struct { + uint32_t lcdcon1; + uint32_t lcdcon2; + uint32_t lcdcon3; + uint32_t lcdcon4; + uint32_t lcdcon5; + uint32_t lcdsaddr1; + uint32_t lcdsaddr2; + uint32_t lcdsaddr3; + uint32_t redlut; + uint32_t greenlut; + uint32_t bluelut; + uint32_t dithmode; + uint32_t tpal; + uint32_t lcdintpnd; + uint32_t lcdsrcpnd; + uint32_t lcdintmsk; + uint32_t lpcsel; + uint32_t __unknown_68; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_lcd_t; + +static int +s3c2410_lcd_data_init(s3c2410_lcd_t *lcd) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(LCD, LCDCON1, 0x00000000, lcd->lcdcon1), + S3C2410_OFFSET(LCD, LCDCON2, 0x00000000, lcd->lcdcon2), + S3C2410_OFFSET(LCD, LCDCON3, 0x00000000, lcd->lcdcon3), + S3C2410_OFFSET(LCD, LCDCON4, 0x00000000, lcd->lcdcon4), + S3C2410_OFFSET(LCD, LCDCON5, 0x00000000, lcd->lcdcon5), + S3C2410_OFFSET(LCD, LCDSADDR1, 0x00000000, lcd->lcdsaddr1), + S3C2410_OFFSET(LCD, LCDSADDR2, 0x00000000, lcd->lcdsaddr2), + S3C2410_OFFSET(LCD, LCDSADDR3, 0x00000000, lcd->lcdsaddr3), + S3C2410_OFFSET(LCD, REDLUT, 0x00000000, lcd->redlut), + S3C2410_OFFSET(LCD, GREENLUT, 0x00000000, lcd->greenlut), + S3C2410_OFFSET(LCD, BLUELUT, 0x00000000, lcd->bluelut), + S3C2410_OFFSET(LCD, DITHMODE, 0x00000000, lcd->dithmode), + S3C2410_OFFSET(LCD, TPAL, 0x00000000, lcd->tpal), + S3C2410_OFFSET(LCD, LCDINTPND, 0x00000000, lcd->lcdintpnd), + S3C2410_OFFSET(LCD, LCDSRCPND, 0x00000000, lcd->lcdsrcpnd), + S3C2410_OFFSET(LCD, LCDINTMSK, 0x00000003, lcd->lcdintmsk), + S3C2410_OFFSET(LCD, LPCSEL, 0x00000004, lcd->lpcsel), + S3C2410_OFFSET(LCD, UNKNOWN_68, 0x00000000, lcd->__unknown_68) + }; + + memset(lcd, 0, sizeof(s3c2410_lcd_t)); + + lcd->regs = malloc(sizeof(regs)); + if (NULL == lcd->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(lcd->regs, regs, sizeof(regs)); + lcd->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +void +x49gp_schedule_lcd_update(x49gp_t *x49gp) +{ + unsigned long ticks; + + ticks = (x49gp->emulator_fclk / x49gp->PCLK_ratio) / 100; + + if (! x49gp_timer_pending(x49gp->lcd_timer)) { + x49gp_mod_timer(x49gp->lcd_timer, + x49gp_get_clock() + X49GP_LCD_REFRESH_INTERVAL); + } +} + +void +x49gp_lcd_update(x49gp_t *x49gp) +{ + x49gp_ui_t *ui = x49gp->ui; + s3c2410_lcd_t *lcd = x49gp->s3c2410_lcd; + GdkRectangle rect; + uint32_t bank, addr, offset, data; + int row, i, b, x, y; + + if (!(lcd->lcdcon1 & 1)) { + gdk_draw_drawable(ui->lcd_pixmap, ui->window->style->bg_gc[0], + ui->bg_pixmap, + ui->lcd_x_offset, ui->lcd_y_offset, + 0, 0, ui->lcd_width, ui->lcd_height); + goto done; + } + + bank = (lcd->lcdsaddr1 << 1) & 0x7fc00000; + addr = bank | ((lcd->lcdsaddr1 << 1) & 0x003ffffe); + + gdk_draw_drawable(ui->lcd_pixmap, ui->window->style->bg_gc[0], + ui->bg_pixmap, + ui->lcd_x_offset, ui->lcd_y_offset, + 0, 0, ui->lcd_width, ui->lcd_height); + + data = ldl_phys(addr + 16); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_io_gc, TRUE, + 236, 0, 15, 12); + } + data = ldl_phys(addr + 36); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_left_gc, TRUE, + 11, 0, 15, 12); + } + data = ldl_phys(addr + 56); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_right_gc, TRUE, + 56, 0, 15, 12); + } + data = ldl_phys(addr + 76); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_alpha_gc, TRUE, + 101, 0, 15, 12); + } + data = ldl_phys(addr + 96); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_battery_gc, TRUE, + 146, 0, 15, 12); + } + data = ldl_phys(addr + 116); + if (data & (1 << 3)) { + gdk_draw_rectangle(ui->lcd_pixmap, ui->ann_busy_gc, TRUE, + 191, 0, 15, 12); + } + + offset = 0; + for (row = 0; row < ui->lcd_height / 2; row++) { + y = 2 * row; + x = 0; + for (i = 0; i < 5; i++) { + data = ldl_phys(addr + offset); + offset += sizeof(uint32_t); + + for (b = 0; b < 32; b++) { + if (data & (1 << b)) { + gdk_draw_rectangle(ui->lcd_pixmap, + ui->window->style->fg_gc[0], + TRUE, x, y + ui->lcd_top_margin, 2, 2); + } + x += 2; + + if (x >= ui->lcd_width) { + break; + } + } + } + } + + addr = bank | ((lcd->lcdsaddr2 << 1) & 0x003ffffe); + +done: + rect.x = 0; + rect.y = 0; + rect.width = ui->lcd_width; + rect.height = ui->lcd_height; + + gdk_window_invalidate_rect(ui->lcd_canvas->window, &rect, FALSE); +} + + +static uint32_t +s3c2410_lcd_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_lcd_t *lcd = opaque; + s3c2410_offset_t *reg; + uint32_t linecnt; + +#ifdef QEMU_OLD + offset -= S3C2410_LCD_BASE; +#endif + if (! S3C2410_OFFSET_OK(lcd, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(lcd, offset); + + switch (offset) { + case S3C2410_LCD_LCDCON1: + linecnt = (lcd->lcdcon1 >> 18) & 0x3ff; + if (linecnt > 0) { + linecnt--; + } else { + linecnt = (lcd->lcdcon2 >> 14) & 0x3ff; + } + + lcd->lcdcon1 &= ~(0x3ff << 18); + lcd->lcdcon1 |= (linecnt << 18); + } + +#ifdef DEBUG_S3C2410_LCD + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-lcd", S3C2410_LCD_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_lcd_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_lcd_t *lcd = opaque; + x49gp_t *x49gp = lcd->x49gp; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_LCD_BASE; +#endif + if (! S3C2410_OFFSET_OK(lcd, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(lcd, offset); + +#ifdef DEBUG_S3C2410_LCD + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-lcd", S3C2410_LCD_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_LCD_LCDCON1: + if ((lcd->lcdcon1 ^ data) & 1) { + x49gp_schedule_lcd_update(x49gp); + } + + lcd->lcdcon1 = (lcd->lcdcon1 & (0x3ff << 18)) | + (data & ~(0x3ff << 18)); + break; + default: + *(reg->datap) = data; + break; + } +} + + +static int +s3c2410_lcd_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_lcd_t *lcd = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < lcd->nr_regs; i++) { + reg = &lcd->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_lcd_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_lcd_t *lcd = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < lcd->nr_regs; i++) { + reg = &lcd->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_lcd_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_lcd_t *lcd = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < lcd->nr_regs; i++) { + reg = &lcd->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_lcd_readfn[] = +{ + s3c2410_lcd_read, + s3c2410_lcd_read, + s3c2410_lcd_read +}; + +static CPUWriteMemoryFunc *s3c2410_lcd_writefn[] = +{ + s3c2410_lcd_write, + s3c2410_lcd_write, + s3c2410_lcd_write +}; + +static int +s3c2410_lcd_init(x49gp_module_t *module) +{ + s3c2410_lcd_t *lcd; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + lcd = malloc(sizeof(s3c2410_lcd_t)); + if (NULL == lcd) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_lcd_data_init(lcd)) { + free(lcd); + return -ENOMEM; + } + + module->user_data = lcd; + module->x49gp->s3c2410_lcd = lcd; + lcd->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_lcd_readfn, + s3c2410_lcd_writefn, lcd); +#else + iotype = cpu_register_io_memory(s3c2410_lcd_readfn, + s3c2410_lcd_writefn, lcd); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_LCD_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_lcd_exit(x49gp_module_t *module) +{ + s3c2410_lcd_t *lcd; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + lcd = module->user_data; + if (lcd->regs) + free(lcd->regs); + free(lcd); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_lcd_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-lcd", + s3c2410_lcd_init, + s3c2410_lcd_exit, + s3c2410_lcd_reset, + s3c2410_lcd_load, + s3c2410_lcd_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_memc.c b/s3c2410_memc.c new file mode 100644 index 0000000..e013845 --- /dev/null +++ b/s3c2410_memc.c @@ -0,0 +1,283 @@ +/* $Id: s3c2410_memc.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef struct { + uint32_t bwscon; + uint32_t bankcon0; + uint32_t bankcon1; + uint32_t bankcon2; + uint32_t bankcon3; + uint32_t bankcon4; + uint32_t bankcon5; + uint32_t bankcon6; + uint32_t bankcon7; + uint32_t refresh; + uint32_t banksize; + uint32_t mrsrb6; + uint32_t mrsrb7; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_memc_t; + +static int +s3c2410_memc_data_init(s3c2410_memc_t *memc) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(MEMC, BWSCON, 0x00000000, memc->bwscon), + S3C2410_OFFSET(MEMC, BANKCON0, 0x00000700, memc->bankcon0), + S3C2410_OFFSET(MEMC, BANKCON1, 0x00000700, memc->bankcon1), + S3C2410_OFFSET(MEMC, BANKCON2, 0x00000700, memc->bankcon2), + S3C2410_OFFSET(MEMC, BANKCON3, 0x00000700, memc->bankcon3), + S3C2410_OFFSET(MEMC, BANKCON4, 0x00000700, memc->bankcon4), + S3C2410_OFFSET(MEMC, BANKCON5, 0x00000700, memc->bankcon5), + S3C2410_OFFSET(MEMC, BANKCON6, 0x00018008, memc->bankcon6), + S3C2410_OFFSET(MEMC, BANKCON7, 0x00018008, memc->bankcon7), + S3C2410_OFFSET(MEMC, REFRESH, 0x00ac0000, memc->refresh), + S3C2410_OFFSET(MEMC, BANKSIZE, 0x00000000, memc->banksize), + S3C2410_OFFSET(MEMC, MRSRB6, 0, memc->mrsrb6), + S3C2410_OFFSET(MEMC, MRSRB7, 0, memc->mrsrb7), + }; + + memset(memc, 0, sizeof(s3c2410_memc_t)); + + memc->regs = malloc(sizeof(regs)); + if (NULL == memc->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(memc->regs, regs, sizeof(regs)); + memc->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static uint32_t +s3c2410_memc_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_memc_t *memc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_MEMC_BASE; +#endif + if (! S3C2410_OFFSET_OK(memc, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(memc, offset); + +#ifdef DEBUG_S3C2410_MEMC + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-memc", S3C2410_MEMC_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_memc_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_memc_t *memc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_MEMC_BASE; +#endif + if (! S3C2410_OFFSET_OK(memc, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(memc, offset); + +#ifdef DEBUG_S3C2410_MEMC + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-memc", S3C2410_MEMC_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; + +#ifdef DEBUG_S3C2410_MEMC + printf("%s:%u: env %p\n", __FUNCTION__, __LINE__, memc->x49gp->env); +#endif +} + +static int +s3c2410_memc_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_memc_t *memc = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < memc->nr_regs; i++) { + reg = &memc->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_memc_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_memc_t *memc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < memc->nr_regs; i++) { + reg = &memc->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_memc_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_memc_t *memc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < memc->nr_regs; i++) { + reg = &memc->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_memc_readfn[] = +{ + s3c2410_memc_read, + s3c2410_memc_read, + s3c2410_memc_read +}; + +static CPUWriteMemoryFunc *s3c2410_memc_writefn[] = +{ + s3c2410_memc_write, + s3c2410_memc_write, + s3c2410_memc_write +}; + +static int +s3c2410_memc_init(x49gp_module_t *module) +{ + s3c2410_memc_t *memc; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + memc = malloc(sizeof(s3c2410_memc_t)); + if (NULL == memc) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_memc_data_init(memc)) { + free(memc); + return -ENOMEM; + } + + module->user_data = memc; + memc->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_memc_readfn, + s3c2410_memc_writefn, memc); +#else + iotype = cpu_register_io_memory(s3c2410_memc_readfn, + s3c2410_memc_writefn, memc); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_MEMC_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_memc_exit(x49gp_module_t *module) +{ + s3c2410_memc_t *memc; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + memc = module->user_data; + if (memc->regs) + free(memc->regs); + free(memc); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_memc_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-memc", + s3c2410_memc_init, + s3c2410_memc_exit, + s3c2410_memc_reset, + s3c2410_memc_load, + s3c2410_memc_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_nand.c b/s3c2410_nand.c new file mode 100644 index 0000000..42c4c3f --- /dev/null +++ b/s3c2410_nand.c @@ -0,0 +1,264 @@ +/* $Id: s3c2410_nand.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef struct { + uint32_t nfconf; + uint32_t nfcmd; + uint32_t nfaddr; + uint32_t nfdata; + uint32_t nfstat; + uint32_t nfecc; + + unsigned int nr_regs; + s3c2410_offset_t *regs; +} s3c2410_nand_t; + + +static int +s3c2410_nand_data_init(s3c2410_nand_t *nand) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(NAND, NFCONF, 0x00000000, nand->nfconf), + S3C2410_OFFSET(NAND, NFCMD, 0x00000000, nand->nfcmd), + S3C2410_OFFSET(NAND, NFADDR, 0x00000000, nand->nfaddr), + S3C2410_OFFSET(NAND, NFDATA, 0x00000000, nand->nfdata), + S3C2410_OFFSET(NAND, NFSTAT, 0x00000000, nand->nfstat), + S3C2410_OFFSET(NAND, NFECC, 0x00000000, nand->nfecc), + }; + + memset(nand, 0, sizeof(s3c2410_nand_t)); + + nand->regs = malloc(sizeof(regs)); + if (NULL == nand->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(nand->regs, regs, sizeof(regs)); + nand->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +uint32_t +s3c2410_nand_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_nand_t *nand = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_NAND_BASE; +#endif + if (! S3C2410_OFFSET_OK(nand, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(nand, offset); + +#ifdef DEBUG_S3C2410_NAND + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-nand", S3C2410_NAND_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +void +s3c2410_nand_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_nand_t *nand = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_NAND_BASE; +#endif + if (! S3C2410_OFFSET_OK(nand, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(nand, offset); + +#ifdef DEBUG_S3C2410_NAND + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-nand", S3C2410_NAND_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; +} + + +static int +s3c2410_nand_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_nand_t *nand = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < nand->nr_regs; i++) { + reg = &nand->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_nand_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_nand_t *nand = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < nand->nr_regs; i++) { + reg = &nand->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_nand_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_nand_t *nand = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < nand->nr_regs; i++) { + reg = &nand->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_nand_readfn[] = +{ + s3c2410_nand_read, + s3c2410_nand_read, + s3c2410_nand_read +}; + +static CPUWriteMemoryFunc *s3c2410_nand_writefn[] = +{ + s3c2410_nand_write, + s3c2410_nand_write, + s3c2410_nand_write +}; + +static int +s3c2410_nand_init(x49gp_module_t *module) +{ + s3c2410_nand_t *nand; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + nand = malloc(sizeof(s3c2410_nand_t)); + if (NULL == nand) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_nand_data_init(nand)) { + free(nand); + return -ENOMEM; + } + + module->user_data = nand; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_nand_readfn, + s3c2410_nand_writefn, nand); +#else + iotype = cpu_register_io_memory(s3c2410_nand_readfn, + s3c2410_nand_writefn, nand); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_NAND_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_nand_exit(x49gp_module_t *module) +{ + s3c2410_nand_t *nand; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + nand = module->user_data; + if (nand->regs) + free(nand->regs); + free(nand); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_nand_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-nand", + s3c2410_nand_init, + s3c2410_nand_exit, + s3c2410_nand_reset, + s3c2410_nand_load, + s3c2410_nand_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_power.c b/s3c2410_power.c new file mode 100644 index 0000000..5c109a0 --- /dev/null +++ b/s3c2410_power.c @@ -0,0 +1,375 @@ +/* $Id: s3c2410_power.c,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static const uint32_t EXTCLK = 12000000; + +typedef struct { + uint32_t locktime; + uint32_t mpllcon; + uint32_t upllcon; + uint32_t clkcon; + uint32_t clkslow; + uint32_t clkdivn; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_power_t; + +static int +s3c2410_power_data_init(s3c2410_power_t *power) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(POWER, LOCKTIME, 0x00ffffff, power->locktime), + S3C2410_OFFSET(POWER, MPLLCON, 0x0005c080, power->mpllcon), + S3C2410_OFFSET(POWER, UPLLCON, 0x00028080, power->upllcon), + S3C2410_OFFSET(POWER, CLKCON, 0x0007fff0, power->clkcon), + S3C2410_OFFSET(POWER, CLKSLOW, 0x00000004, power->clkslow), + S3C2410_OFFSET(POWER, CLKDIVN, 0x00000000, power->clkdivn) + }; + + memset(power, 0, sizeof(s3c2410_power_t)); + + power->regs = malloc(sizeof(regs)); + if (NULL == power->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(power->regs, regs, sizeof(regs)); + power->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static uint32_t +s3c2410_power_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_power_t *power = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_POWER_BASE; +#endif + if (! S3C2410_OFFSET_OK(power, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(power, offset); + +#ifdef DEBUG_S3C2410_POWER + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-power", S3C2410_POWER_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_power_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_power_t *power = opaque; + x49gp_t *x49gp = power->x49gp; + s3c2410_offset_t *reg; + uint32_t mMdiv, mPdiv, mSdiv; + uint32_t uMdiv, uPdiv, uSdiv; + uint32_t slow_bit, slow_val; + +#ifdef QEMU_OLD + offset -= S3C2410_POWER_BASE; +#endif + if (! S3C2410_OFFSET_OK(power, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(power, offset); + +#ifdef DEBUG_S3C2410_POWER + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-power", S3C2410_POWER_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_POWER_CLKCON: + if (data & CLKCON_POWER_OFF) { + *(reg->datap) = 0x7fff0; +#ifdef DEBUG_S3C2410_POWER + printf("POWER: enter POWER_OFF\n"); +#endif + + x49gp_modules_reset(x49gp, X49GP_RESET_POWER_OFF); + +// if (x49gp->arm->NresetSig != LOW) { +// x49gp->arm->NresetSig = LOW; +// x49gp->arm->Exception++; +// } + x49gp_set_idle(x49gp, X49GP_ARM_OFF); + return; + } + + if (!(power->clkcon & CLKCON_IDLE) && (data & CLKCON_IDLE)) { + *(reg->datap) = data; +#ifdef DEBUG_S3C2410_POWER + printf("POWER: enter IDLE\n"); +#endif + x49gp_set_idle(x49gp, X49GP_ARM_SLEEP); + return; + } + + *(reg->datap) = data; + return; + + case S3C2410_POWER_LOCKTIME: + *(reg->datap) = data; + return; + + default: + *(reg->datap) = data; + break; + } + + mMdiv = (power->mpllcon >> 12) & 0xff; + mPdiv = (power->mpllcon >> 4) & 0x3f; + mSdiv = (power->mpllcon >> 0) & 0x03; + x49gp->MCLK = (((u64) EXTCLK) * ((u64) (mMdiv + 8))) / ((u64) ((mPdiv + 2) * (1 << mSdiv))); + + uMdiv = (power->upllcon >> 12) & 0xff; + uPdiv = (power->upllcon >> 4) & 0x3f; + uSdiv = (power->upllcon >> 0) & 0x03; + x49gp->UCLK = (((u64) EXTCLK) * ((u64) (uMdiv + 8))) / ((u64) ((uPdiv + 2) * (1 << uSdiv))); + + slow_bit = (power->clkslow & 0x10); + if (slow_bit) { + slow_val = (power->clkslow >> 0) & 0x07; + if (0 == slow_val) + x49gp->FCLK = EXTCLK; + else + x49gp->FCLK = EXTCLK / (2 * slow_val); + } else { + x49gp->FCLK = x49gp->MCLK; + } + + if (power->clkdivn & 4) { + x49gp->HCLK = x49gp->FCLK / 4; + x49gp->PCLK = x49gp->FCLK / 4; + x49gp->PCLK_ratio = 4; + } else { + switch (power->clkdivn & 3) { + case 0: + x49gp->HCLK = x49gp->FCLK; + x49gp->PCLK = x49gp->HCLK; + x49gp->PCLK_ratio = 1; + break; + case 1: + x49gp->HCLK = x49gp->FCLK; + x49gp->PCLK = x49gp->HCLK / 2; + x49gp->PCLK_ratio = 2; + break; + case 2: + x49gp->HCLK = x49gp->FCLK / 2; + x49gp->PCLK = x49gp->HCLK; + x49gp->PCLK_ratio = 2; + break; + case 3: + x49gp->HCLK = x49gp->FCLK / 2; + x49gp->PCLK = x49gp->HCLK / 2; + x49gp->PCLK_ratio = 4; + break; + } + } + +#ifdef DEBUG_S3C2410_POWER + printf("%s: EXTCLK %u, mdiv %u, pdiv %u, sdiv %u: MCLK %u\n", + __FUNCTION__, EXTCLK, mMdiv, mPdiv, mSdiv, x49gp->MCLK); + printf("%s: EXTCLK %u, mdiv %u, pdiv %u, sdiv %u: UCLK %u\n", + __FUNCTION__, EXTCLK, uMdiv, uPdiv, uSdiv, x49gp->UCLK); + printf("%s: FCLK %s: %u\n", + __FUNCTION__, slow_bit ? "(slow)" : "", x49gp->FCLK); + printf("%s: HCLK %u, PCLK %u\n", + __FUNCTION__, x49gp->HCLK, x49gp->PCLK); +#endif +} + +static int +s3c2410_power_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_power_t *power = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < power->nr_regs; i++) { + reg = &power->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + if (error) { + return error; + } + + s3c2410_power_write(power, S3C2410_POWER_BASE | S3C2410_POWER_CLKDIVN, + power->clkdivn); + return 0; +} + +static int +s3c2410_power_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_power_t *power = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < power->nr_regs; i++) { + reg = &power->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_power_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_power_t *power = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < power->nr_regs; i++) { + reg = &power->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_power_readfn[] = +{ + s3c2410_power_read, + s3c2410_power_read, + s3c2410_power_read +}; + +static CPUWriteMemoryFunc *s3c2410_power_writefn[] = +{ + s3c2410_power_write, + s3c2410_power_write, + s3c2410_power_write +}; + +static int +s3c2410_power_init(x49gp_module_t *module) +{ + s3c2410_power_t *power; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + power = malloc(sizeof(s3c2410_power_t)); + if (NULL == power) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_power_data_init(power)) { + free(power); + return -ENOMEM; + } + + module->user_data = power; + power->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_power_readfn, + s3c2410_power_writefn, power); +#else + iotype = cpu_register_io_memory(s3c2410_power_readfn, + s3c2410_power_writefn, power); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_POWER_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_power_exit(x49gp_module_t *module) +{ + s3c2410_power_t *power; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + power = module->user_data; + if (power->regs) + free(power->regs); + free(power); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_power_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-power", + s3c2410_power_init, + s3c2410_power_exit, + s3c2410_power_reset, + s3c2410_power_load, + s3c2410_power_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_rtc.c b/s3c2410_rtc.c new file mode 100644 index 0000000..4699b83 --- /dev/null +++ b/s3c2410_rtc.c @@ -0,0 +1,514 @@ +/* $Id: s3c2410_rtc.c,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct { + uint32_t rtccon; + uint32_t ticnt; + uint32_t rtcalm; + uint32_t almsec; + uint32_t almmin; + uint32_t almhour; + uint32_t almdate; + uint32_t almmon; + uint32_t almyear; + uint32_t rtcrst; + uint32_t bcdsec; + uint32_t bcdmin; + uint32_t bcdhour; + uint32_t bcddate; + uint32_t bcdday; + uint32_t bcdmon; + uint32_t bcdyear; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; + x49gp_timer_t *tick_timer; + x49gp_timer_t *alarm_timer; + int64_t interval; /* us */ + int64_t expires; /* us */ +} s3c2410_rtc_t; + + +static int +s3c2410_rtc_data_init(s3c2410_rtc_t *rtc) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(RTC, RTCCON, 0x00, rtc->rtccon), + S3C2410_OFFSET(RTC, TICNT, 0x00, rtc->ticnt), + S3C2410_OFFSET(RTC, RTCALM, 0x00, rtc->rtcalm), + S3C2410_OFFSET(RTC, ALMSEC, 0x00, rtc->almsec), + S3C2410_OFFSET(RTC, ALMMIN, 0x00, rtc->almmin), + S3C2410_OFFSET(RTC, ALMHOUR, 0x00, rtc->almhour), + S3C2410_OFFSET(RTC, ALMDATE, 0x01, rtc->almdate), + S3C2410_OFFSET(RTC, ALMMON, 0x01, rtc->almmon), + S3C2410_OFFSET(RTC, ALMYEAR, 0x00, rtc->almyear), + S3C2410_OFFSET(RTC, RTCRST, 0x00, rtc->rtcrst), + S3C2410_OFFSET(RTC, BCDSEC, 0, rtc->bcdsec), + S3C2410_OFFSET(RTC, BCDMIN, 0, rtc->bcdmin), + S3C2410_OFFSET(RTC, BCDHOUR, 0, rtc->bcdhour), + S3C2410_OFFSET(RTC, BCDDATE, 0, rtc->bcddate), + S3C2410_OFFSET(RTC, BCDDAY, 0, rtc->bcdday), + S3C2410_OFFSET(RTC, BCDMON, 0, rtc->bcdmon), + S3C2410_OFFSET(RTC, BCDYEAR, 0, rtc->bcdyear) + }; + + memset(rtc, 0, sizeof(s3c2410_rtc_t)); + + rtc->regs = malloc(sizeof(regs)); + if (NULL == rtc->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(rtc->regs, regs, sizeof(regs)); + rtc->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static __inline__ uint32_t bin2bcd(uint32_t bin) +{ + return ((bin / 10) << 4) | (bin % 10); +} + +static __inline__ uint32_t bcd2bin(uint32_t bcd) +{ + return ((bcd >> 4) * 10) + (bcd & 0x0f); +} + +static void +s3c2410_rtc_timeout(void * user_data) +{ + s3c2410_rtc_t *rtc = user_data; + x49gp_t *x49gp = rtc->x49gp; + int64_t now, us; + + if (!(rtc->ticnt & 0x80)) { + return; + } + +#ifdef DEBUG_S3C2410_RTC + printf("RTC: assert TICK interrupt\n"); +#endif + + s3c2410_intc_assert(x49gp, INT_TICK, 0); + + now = x49gp_get_clock(); + while (rtc->expires <= now) { + rtc->expires += rtc->interval; + } + + us = rtc->expires - now; + if (us < 1000) + us = 1000; + +#ifdef DEBUG_S3C2410_RTC + printf("RTC: restart TICK timer (%llu us)\n", us); +#endif + + x49gp_mod_timer(rtc->tick_timer, rtc->expires); +} + +static int +s3c2410_rtc_set_ticnt(s3c2410_rtc_t *rtc) +{ + int64_t now, us; + + if (x49gp_timer_pending(rtc->tick_timer)) { + x49gp_del_timer(rtc->tick_timer); +#ifdef DEBUG_S3C2410_RTC + printf("RTC: stop TICK timer\n"); +#endif + } + + if (!(rtc->ticnt & 0x80)) { + return 0; + } + + us = (((rtc->ticnt & 0x7f) + 1) * 1000000) / 128; + + rtc->interval = us; + if (rtc->interval < 1000) + rtc->interval = 1000; + + now = x49gp_get_clock(); + rtc->expires = now + rtc->interval; + + us = rtc->expires - now; + if (us < 1000) + us = 1000; + +#ifdef DEBUG_S3C2410_RTC + printf("RTC: start TICK timer (%lld us)\n", us); +#endif + + x49gp_mod_timer(rtc->tick_timer, rtc->expires); + return 0; +} + +static void +s3c2410_rtc_alarm(void * user_data) +{ + s3c2410_rtc_t *rtc = user_data; + x49gp_t *x49gp = rtc->x49gp; + struct tm *tm; + struct timeval tv; + int64_t now, us; + int match = 1; + + if (!(rtc->rtcalm & 0x40)) { + return; + } + + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + + now = x49gp_get_clock(); + us = 1000000LL - tv.tv_usec; + + if (match && (rtc->rtcalm & 0x01)) { + if (tm->tm_sec != bcd2bin(rtc->almsec)) + match = 0; + } + if (match && (rtc->rtcalm & 0x02)) { + if (tm->tm_min != bcd2bin(rtc->almmin)) + match = 0; + } + if (match && (rtc->rtcalm & 0x04)) { + if (tm->tm_hour != bcd2bin(rtc->almhour)) + match = 0; + } + if (match && (rtc->rtcalm & 0x08)) { + if (tm->tm_mday != bcd2bin(rtc->almdate)) + match = 0; + } + if (match && (rtc->rtcalm & 0x10)) { + if ((tm->tm_mon + 1) != bcd2bin(rtc->almmon)) + match = 0; + } + if (match && (rtc->rtcalm & 0x20)) { + if ((tm->tm_year % 100) != bcd2bin(rtc->almyear)) + match = 0; + } + + if (match) { +#ifdef DEBUG_S3C2410_RTC + printf("RTC: assert ALARM interrupt\n"); +#endif + s3c2410_intc_assert(x49gp, INT_RTC, 0); + } + +#ifdef DEBUG_S3C2410_RTC + printf("RTC: reload ALARM timer (%lld us)\n", us); +#endif + + x49gp_mod_timer(rtc->alarm_timer, now + us); +} + +static int +s3c2410_rtc_set_rtcalm(s3c2410_rtc_t *rtc) +{ + struct tm *tm; + struct timeval tv; + int64_t now, us; + + if (!(rtc->rtcalm & 0x40)) { + x49gp_del_timer(rtc->alarm_timer); + return 0; + } + + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + + now = x49gp_get_clock(); + us = 1000000LL - tv.tv_usec; + +#ifdef DEBUG_S3C2410_RTC + printf("RTC: start ALARM timer (%lld us)\n", us); +#endif + + x49gp_mod_timer(rtc->alarm_timer, now + us); + return 0; +} + +static uint32_t +s3c2410_rtc_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_rtc_t *rtc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_RTC_BASE; +#endif + if (! S3C2410_OFFSET_OK(rtc, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(rtc, offset); + + if (S3C2410_RTC_BCDSEC <= offset && offset <= S3C2410_RTC_BCDYEAR) { + struct tm *tm; + time_t t; + + t = time(0); + tm = localtime(&t); + + switch (offset) { + case S3C2410_RTC_BCDSEC: + *(reg->datap) = bin2bcd(tm->tm_sec); + break; + case S3C2410_RTC_BCDMIN: + *(reg->datap) = bin2bcd(tm->tm_min); + break; + case S3C2410_RTC_BCDHOUR: + *(reg->datap) = bin2bcd(tm->tm_hour); + break; + case S3C2410_RTC_BCDDATE: + *(reg->datap) = bin2bcd(tm->tm_mday); + break; + case S3C2410_RTC_BCDDAY: + *(reg->datap) = bin2bcd(tm->tm_wday + 1); + break; + case S3C2410_RTC_BCDMON: + *(reg->datap) = bin2bcd(tm->tm_mon + 1); + break; + case S3C2410_RTC_BCDYEAR: + *(reg->datap) = bin2bcd(tm->tm_year % 100); + break; + } + } + +#ifdef DEBUG_S3C2410_RTC + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-rtc", S3C2410_RTC_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_rtc_t *rtc = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_RTC_BASE; +#endif + if (! S3C2410_OFFSET_OK(rtc, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(rtc, offset); + +#ifdef DEBUG_S3C2410_RTC + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-rtc", S3C2410_RTC_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_RTC_TICNT: + *(reg->datap) = data; + s3c2410_rtc_set_ticnt(rtc); + break; + case S3C2410_RTC_RTCALM: + *(reg->datap) = data; + s3c2410_rtc_set_rtcalm(rtc); + break; + default: + *(reg->datap) = data; + break; + } +} + +static int +s3c2410_rtc_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_rtc_t *rtc = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < rtc->nr_regs; i++) { + reg = &rtc->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + s3c2410_rtc_set_ticnt(rtc); + s3c2410_rtc_set_rtcalm(rtc); + + return error; +} + +static int +s3c2410_rtc_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_rtc_t *rtc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < rtc->nr_regs; i++) { + reg = &rtc->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_rtc_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_rtc_t *rtc = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < (S3C2410_RTC_RTCALM >> 2); i++) { + reg = &rtc->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + s3c2410_rtc_set_ticnt(rtc); + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_rtc_readfn[] = +{ + s3c2410_rtc_read, + s3c2410_rtc_read, + s3c2410_rtc_read +}; + +static CPUWriteMemoryFunc *s3c2410_rtc_writefn[] = +{ + s3c2410_rtc_write, + s3c2410_rtc_write, + s3c2410_rtc_write +}; + +static int +s3c2410_rtc_init(x49gp_module_t *module) +{ + s3c2410_rtc_t *rtc; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + rtc = malloc(sizeof(s3c2410_rtc_t)); + if (NULL == rtc) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->x49gp->progname, __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_rtc_data_init(rtc)) { + free(rtc); + return -ENOMEM; + } + + module->user_data = rtc; + rtc->x49gp = module->x49gp; + + rtc->tick_timer = x49gp_new_timer(X49GP_TIMER_REALTIME, + s3c2410_rtc_timeout, rtc); + rtc->alarm_timer = x49gp_new_timer(X49GP_TIMER_REALTIME, + s3c2410_rtc_alarm, rtc); + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_rtc_readfn, + s3c2410_rtc_writefn, rtc); +#else + iotype = cpu_register_io_memory(s3c2410_rtc_readfn, + s3c2410_rtc_writefn, rtc); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_RTC_BASE, S3C2410_MAP_SIZE, iotype); + + return 0; +} + +static int +s3c2410_rtc_exit(x49gp_module_t *module) +{ + s3c2410_rtc_t *rtc; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + rtc = module->user_data; + if (rtc->regs) + free(rtc->regs); + free(rtc); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_rtc_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-rtc", + s3c2410_rtc_init, + s3c2410_rtc_exit, + s3c2410_rtc_reset, + s3c2410_rtc_load, + s3c2410_rtc_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_sdi.c b/s3c2410_sdi.c new file mode 100644 index 0000000..5e6386d --- /dev/null +++ b/s3c2410_sdi.c @@ -0,0 +1,722 @@ +/* $Id: s3c2410_sdi.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +typedef struct { + uint32_t sdicon; + uint32_t sdipre; + uint32_t sdicarg; + uint32_t sdiccon; + uint32_t sdicsta; + uint32_t sdirsp0; + uint32_t sdirsp1; + uint32_t sdirsp2; + uint32_t sdirsp3; + uint32_t sdidtimer; + uint32_t sdibsize; + uint32_t sdidcon; + uint32_t sdidcnt; + uint32_t sdidsta; + uint32_t sdifsta; + uint32_t sdidat; + uint32_t sdiimsk; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; + + BlockDriverState *bs; + int fd; + + unsigned char *read_data; + uint32_t nr_read_data; + uint32_t read_offset; + unsigned int read_index; + + unsigned char *write_data; + uint32_t nr_write_data; + uint32_t write_offset; + unsigned int write_index; + + int multiple_block; +} s3c2410_sdi_t; + + +static int +s3c2410_sdi_data_init(s3c2410_sdi_t *sdi) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(SDI, SDICON, 0x00000000, sdi->sdicon), + S3C2410_OFFSET(SDI, SDIPRE, 0x00000000, sdi->sdipre), + S3C2410_OFFSET(SDI, SDICARG, 0x00000000, sdi->sdicarg), + S3C2410_OFFSET(SDI, SDICCON, 0x00000000, sdi->sdiccon), + S3C2410_OFFSET(SDI, SDICSTA, 0x00000000, sdi->sdicsta), + S3C2410_OFFSET(SDI, SDIRSP0, 0x00000000, sdi->sdirsp0), + S3C2410_OFFSET(SDI, SDIRSP1, 0x00000000, sdi->sdirsp1), + S3C2410_OFFSET(SDI, SDIRSP2, 0x00000000, sdi->sdirsp2), + S3C2410_OFFSET(SDI, SDIRSP3, 0x00000000, sdi->sdirsp3), + S3C2410_OFFSET(SDI, SDIDTIMER, 0x00002000, sdi->sdidtimer), + S3C2410_OFFSET(SDI, SDIBSIZE, 0x00000000, sdi->sdibsize), + S3C2410_OFFSET(SDI, SDIDCON, 0x00000000, sdi->sdidcon), + S3C2410_OFFSET(SDI, SDIDCNT, 0x00000000, sdi->sdidcnt), + S3C2410_OFFSET(SDI, SDIDSTA, 0x00000000, sdi->sdidsta), + S3C2410_OFFSET(SDI, SDIFSTA, 0x00000000, sdi->sdifsta), + S3C2410_OFFSET(SDI, SDIDAT, 0x00000000, sdi->sdidat), + S3C2410_OFFSET(SDI, SDIIMSK, 0x00000000, sdi->sdiimsk) + }; + + memset(sdi, 0, sizeof(s3c2410_sdi_t)); + + sdi->regs = malloc(sizeof(regs)); + if (NULL == sdi->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(sdi->regs, regs, sizeof(regs)); + sdi->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static int +sdcard_read(s3c2410_sdi_t *sdi) +{ + uint32_t offset; + uint32_t size; + int error; + + offset = sdi->read_offset; + size = sdi->nr_read_data; + +#ifdef DEBUG_S3C2410_SDI + printf("SDI: card read %4u at %08x\n", size, offset); +#endif + + sdi->nr_read_data = 0; + sdi->read_index = 0; + + if ((sdi->fd < 0) && (sdi->bs == NULL)) { + return -ENODEV; + } + + sdi->read_data = malloc(size); + if (NULL == sdi->read_data) { + return -ENOMEM; + } + + if (sdi->bs) { + sdi->nr_read_data = bdrv_pread(sdi->bs, offset, sdi->read_data, size); + } else { + if (sdi->read_offset != lseek(sdi->fd, offset, SEEK_SET)) { + error = errno; + sdi->nr_read_data = 0; + free(sdi->read_data); + sdi->read_data = NULL; + return -error; + } + + sdi->nr_read_data = read(sdi->fd, sdi->read_data, size); + } + + if (sdi->nr_read_data != size) { + error = errno; + sdi->nr_read_data = 0; + free(sdi->read_data); + sdi->read_data = NULL; + return -error; + } + + return 0; +} + +static int +sdcard_write_prepare(s3c2410_sdi_t *sdi) +{ + sdi->write_index = 0; + + if ((sdi->fd < 0) && (sdi->bs == NULL)) { + sdi->nr_write_data = 0; + return -ENODEV; + } + + sdi->write_data = malloc(sdi->nr_write_data); + if (NULL == sdi->write_data) { + sdi->nr_write_data = 0; + return -ENOMEM; + } + + return 0; +} + +static int +sdcard_write(s3c2410_sdi_t *sdi) +{ + uint32_t offset; + uint32_t size; + int error; + + offset = sdi->write_offset; + size = sdi->nr_write_data; + +#ifdef DEBUG_S3C2410_SDI + printf("SDI: card write %4u at %08x\n", size, offset); +#endif + + sdi->write_index = 0; + + if (sdi->bs) { + error = bdrv_pwrite(sdi->bs, offset, sdi->write_data, size); + } else { + if (sdi->fd < 0) { + free(sdi->write_data); + sdi->write_data = NULL; + return -ENODEV; + } + + if (sdi->write_offset != lseek(sdi->fd, offset, SEEK_SET)) { + error = errno; + free(sdi->write_data); + sdi->write_data = NULL; + return -error; + } + + error = write(sdi->fd, sdi->write_data, size); + } + + if (error != size) { + error = errno; + free(sdi->write_data); + sdi->write_data = NULL; + return -error; + } + + free(sdi->write_data); + sdi->write_data = NULL; + return 0; +} + +static uint32_t +s3c2410_sdi_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_sdi_t *sdi = opaque; + s3c2410_offset_t *reg; + unsigned int read_avail, write_avail; + +#ifdef QEMU_OLD + offset -= S3C2410_SDI_BASE; +#endif + if (! S3C2410_OFFSET_OK(sdi, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(sdi, offset); + + switch (offset) { + case S3C2410_SDI_SDIDAT: + read_avail = sdi->nr_read_data - sdi->read_index; + if (read_avail > 0) { + *(reg->datap) = sdi->read_data[sdi->read_index++] << 24; + if ((sdi->nr_read_data - sdi->read_index) > 0) { + *(reg->datap) |= sdi->read_data[sdi->read_index++] << 16; + } + if ((sdi->nr_read_data - sdi->read_index) > 0) { + *(reg->datap) |= sdi->read_data[sdi->read_index++] << 8; + } + if ((sdi->nr_read_data - sdi->read_index) > 0) { + *(reg->datap) |= sdi->read_data[sdi->read_index++] << 0; + } + + if (sdi->read_index >= sdi->nr_read_data) { + sdi->read_index = 0; + free(sdi->read_data); + sdi->read_data = NULL; + + if (sdi->multiple_block) { + sdi->read_offset += sdi->nr_read_data; + + sdcard_read(sdi); + + sdi->sdidsta |= (1 << 9) | (1 << 4); + } else { + sdi->nr_read_data = 0; + } + } + + read_avail = sdi->nr_read_data - sdi->read_index; + + sdi->sdidcnt = read_avail; + } + break; + + case S3C2410_SDI_SDIFSTA: + *(reg->datap) = (1 << 13) | (1 << 10); + + read_avail = sdi->nr_read_data - sdi->read_index; + if (read_avail > 63) + *(reg->datap) |= (1 << 12) | (1 << 8) | (1 << 7) | 0x40; + else if (read_avail > 31) + *(reg->datap) |= (1 << 12) | (1 << 9) | (1 << 7) | read_avail; + else + *(reg->datap) |= (1 << 12) | (1 << 9) | read_avail; + break; + + case S3C2410_SDI_SDIDSTA: + *(reg->datap) &= ~(0x0f); + + read_avail = sdi->nr_read_data - sdi->read_index; + if (read_avail) { + *(reg->datap) |= (1 << 0); + } + + write_avail = sdi->nr_write_data - sdi->write_index; + if (write_avail) { + *(reg->datap) |= (1 << 1); + } + } + +#ifdef DEBUG_S3C2410_SDI + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-sdi", S3C2410_SDI_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_sdi_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_sdi_t *sdi = opaque; + s3c2410_offset_t *reg; + unsigned int read_avail, write_avail; + +#ifdef QEMU_OLD + offset -= S3C2410_SDI_BASE; +#endif + if (! S3C2410_OFFSET_OK(sdi, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(sdi, offset); + +#ifdef DEBUG_S3C2410_SDI + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-sdi", S3C2410_SDI_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_SDI_SDICON: + *(reg->datap) = data & ~(2); + break; + + case S3C2410_SDI_SDICCON: + *(reg->datap) = data; + +#ifdef DEBUG_S3C2410_SDI + printf("SDI: cmd %02u, start %u, %s response %u, data %u, abort %u\n", + data & 0x3f, (data >> 8) & 1, + (data >> 10) & 1 ? "long" : "short", + (data >> 9) & 1, + (data >> 11) & 1, (data >> 12) & 1); +#endif + + if (data & (1 << 8)) { + sdi->sdicsta |= (1 << 11); + } else { + sdi->sdicsta = 0; + sdi->sdirsp0 = 0; + sdi->sdirsp1 = 0; + sdi->sdirsp2 = 0; + sdi->sdirsp3 = 0; + data = 0; + } + + sdi->sdicsta &= ~(1 << 12); + sdi->sdicsta &= ~(0xff); + + if (data & (1 << 9)) { + sdi->sdicsta |= (1 << 9); + + switch (data & 0x3f) { + case 0: + break; + + case 1: + sdi->sdicsta |= 0x3f; + sdi->sdirsp0 = 0x80ff8000; + sdi->sdirsp1 = 0xff000000; + break; + + case 2: + sdi->sdicsta |= 0x3f; + sdi->sdirsp0 = 0x02000053; + sdi->sdirsp1 = 0x444d3036; + sdi->sdirsp2 = 0x34011234; + sdi->sdirsp3 = 0x567813ff; + break; + + case 3: + sdi->sdicsta |= 3; + sdi->sdirsp0 = 0x00000700; + sdi->sdirsp1 = 0xff000000; + break; + + case 7: + sdi->sdicsta |= 7; + sdi->sdirsp0 = 0x00000900; + sdi->sdirsp1 = 0xff000000; + break; + + case 9: + { + /* c_size_mult + 2 + * blocks = (c_size + 1) * 2 + * + * size = bl_len * blocks; + */ + uint32_t write_bl_len = 9; + uint32_t read_bl_len = 9; + uint32_t c_size_mult = 7; + uint32_t c_size = 256 - 1; + + sdi->sdicsta |= 9; + /* 127 .. 96 */ + sdi->sdirsp0 = 0x8c0f002a; + /* 95 .. 64 */ + sdi->sdirsp1 = 0x0f508000 | ((c_size & 0xffc) >> 2) | ((read_bl_len & 0xf) << 16); + /* 63 .. 32 */ + sdi->sdirsp2 = 0x2dd47c1f | ((c_size & 0x003) << 30) | ((c_size_mult & 7) << 15); + /* 31 .. 0 */ + sdi->sdirsp3 = 0x8a0040ff | ((write_bl_len & 0xf) << 22); + break; + } + + case 10: + sdi->sdicsta |= 10; + sdi->sdirsp0 = 0x02000053; + sdi->sdirsp1 = 0x444d3036; + sdi->sdirsp2 = 0x34011234; + sdi->sdirsp3 = 0x567813ff; + break; + + case 12: + sdi->multiple_block = 0; + + sdi->sdicsta |= 12; + sdi->sdirsp0 = 0x00000900; + sdi->sdirsp1 = 0xff000000; + break; + + case 18: + sdi->multiple_block = 1; + /* fall through */ + case 17: + sdi->read_offset = sdi->sdicarg; + sdi->nr_read_data = sdi->sdibsize & 0xfff; + + sdcard_read(sdi); + + read_avail = sdi->nr_read_data - sdi->read_index; + + sdi->sdicsta |= data & 0x3f; + sdi->sdirsp0 = 0x00000b00; + sdi->sdirsp1 = 0xff000000; + sdi->sdidcnt = (1 << 12) | read_avail; + sdi->sdidsta |= (1 << 9) | (1 << 4); + break; + + case 25: + sdi->multiple_block = 1; + /* fall through */ + case 24: + sdi->write_offset = sdi->sdicarg; + sdi->nr_write_data = sdi->sdibsize & 0xfff; + + sdcard_write_prepare(sdi); + + write_avail = sdi->nr_write_data - sdi->write_index; + + sdi->sdicsta |= data & 0x3f; + sdi->sdirsp0 = 0x00000d00; + sdi->sdirsp1 = 0xff000000; + sdi->sdidcnt = (1 << 12) | write_avail; + break; + + default: + printf("unhandled SDcard CMD %u\n", (data & 0x3f)); + + sdi->sdicsta |= (1 << 10); + sdi->sdicsta &= ~(1 << 9); + +// abort(); + break; + } + } + + break; + + case S3C2410_SDI_SDIDAT: + *(reg->datap) = data; + + write_avail = sdi->nr_write_data - sdi->write_index; + if (write_avail > 0) { + sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 24) & 0xff; + if ((sdi->nr_write_data - sdi->write_index) > 0) { + sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 16) & 0xff; + } + if ((sdi->nr_write_data - sdi->write_index) > 0) { + sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 8) & 0xff; + } + if ((sdi->nr_write_data - sdi->write_index) > 0) { + sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 0) & 0xff; + } + + if (sdi->write_index >= sdi->nr_write_data) { + sdcard_write(sdi); + + if (sdi->multiple_block) { + sdi->write_offset += sdi->nr_write_data; + sdcard_write_prepare(sdi); + } else { + sdi->nr_write_data = 0; + } + + sdi->sdidsta |= (1 << 9) | (1 << 4); + } + + write_avail = sdi->nr_write_data - sdi->write_index; + + sdi->sdidcnt = write_avail; + } + break; + + case S3C2410_SDI_SDICSTA: + *(reg->datap) &= ~(data & 0xf00); + break; + + case S3C2410_SDI_SDIDSTA: + *(reg->datap) &= ~(data & 0x3f8); + break; + + case S3C2410_SDI_SDIFSTA: + /* ignore */ + break; + + default: + *(reg->datap) = data; + break; + } +} + +static int +s3c2410_sdi_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_sdi_t *sdi = module->user_data; + s3c2410_offset_t *reg; + char *filename; + char vvfat_name[1024]; + struct stat st; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + sdi->fd = -1; + sdi->bs = NULL; + + filename = x49gp_module_get_filename(module, key, "filename"); + if (filename && (stat(filename, &st) == 0)) { + if (S_ISDIR(st.st_mode)) { + sprintf(vvfat_name, "fat:rw:16:%s", filename); + sdi->bs = bdrv_new(""); + if (sdi->bs) { + error = bdrv_open(sdi->bs, vvfat_name, 0); + fprintf(stderr, "%s:%u: bdrv_open(%s): %d\n", + __FUNCTION__, __LINE__, vvfat_name, error); + if (error != 0) { + bdrv_delete(sdi->bs); + sdi->bs = NULL; + } + } + } else { + sdi->fd = open(filename, O_RDWR); + } + g_free(filename); + } + + if ((sdi->bs != NULL) || (sdi->fd >= 0)) { + s3c2410_io_port_f_set_bit(sdi->x49gp, 3, 1); + } else { + s3c2410_io_port_f_set_bit(sdi->x49gp, 3, 0); + } + + for (i = 0; i < sdi->nr_regs; i++) { + reg = &sdi->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_sdi_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_sdi_t *sdi = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < sdi->nr_regs; i++) { + reg = &sdi->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_sdi_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_sdi_t *sdi = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < sdi->nr_regs; i++) { + reg = &sdi->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_sdi_readfn[] = +{ + s3c2410_sdi_read, + s3c2410_sdi_read, + s3c2410_sdi_read +}; + +static CPUWriteMemoryFunc *s3c2410_sdi_writefn[] = +{ + s3c2410_sdi_write, + s3c2410_sdi_write, + s3c2410_sdi_write +}; + +static int +s3c2410_sdi_init(x49gp_module_t *module) +{ + s3c2410_sdi_t *sdi; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + sdi = malloc(sizeof(s3c2410_sdi_t)); + if (NULL == sdi) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->x49gp->progname, __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_sdi_data_init(sdi)) { + free(sdi); + return -ENOMEM; + } + + module->user_data = sdi; + sdi->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_sdi_readfn, + s3c2410_sdi_writefn, sdi); +#else + iotype = cpu_register_io_memory(s3c2410_sdi_readfn, + s3c2410_sdi_writefn, sdi); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_SDI_BASE, S3C2410_MAP_SIZE, iotype); + + bdrv_init(); + return 0; +} + +static int +s3c2410_sdi_exit(x49gp_module_t *module) +{ + s3c2410_sdi_t *sdi; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + sdi = module->user_data; + if (sdi->regs) + free(sdi->regs); + free(sdi); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_sdi_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-sdi", + s3c2410_sdi_init, + s3c2410_sdi_exit, + s3c2410_sdi_reset, + s3c2410_sdi_load, + s3c2410_sdi_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_spi.c b/s3c2410_spi.c new file mode 100644 index 0000000..4b04677 --- /dev/null +++ b/s3c2410_spi.c @@ -0,0 +1,302 @@ +/* $Id: s3c2410_spi.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct { + uint32_t spicon0; + uint32_t spista0; + uint32_t sppin0; + uint32_t sppre0; + uint32_t sptdat0; + uint32_t sprdat0; + uint32_t spicon1; + uint32_t spista1; + uint32_t sppin1; + uint32_t sppre1; + uint32_t sptdat1; + uint32_t sprdat1; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_spi_t; + +static int +s3c2410_spi_data_init(s3c2410_spi_t *spi) +{ + s3c2410_offset_t regs[] = + { + S3C2410_OFFSET(SPI, SPICON0, 0x00000000, spi->spicon0), + S3C2410_OFFSET(SPI, SPISTA0, 0x00000000, spi->spista0), + S3C2410_OFFSET(SPI, SPPIN0, 0x00000000, spi->sppin0), + S3C2410_OFFSET(SPI, SPPRE0, 0x00000000, spi->sppre0), + S3C2410_OFFSET(SPI, SPTDAT0, 0x00000000, spi->sptdat0), + S3C2410_OFFSET(SPI, SPRDAT0, 0x00000000, spi->sprdat0), + S3C2410_OFFSET(SPI, SPICON1, 0x00000000, spi->spicon1), + S3C2410_OFFSET(SPI, SPISTA1, 0x00000000, spi->spista1), + S3C2410_OFFSET(SPI, SPPIN1, 0x00000000, spi->sppin1), + S3C2410_OFFSET(SPI, SPPRE1, 0x00000000, spi->sppre1), + S3C2410_OFFSET(SPI, SPTDAT1, 0x00000000, spi->sptdat1), + S3C2410_OFFSET(SPI, SPRDAT1, 0x00000000, spi->sprdat1), + }; + + memset(spi, 0, sizeof(s3c2410_spi_t)); + + spi->regs = malloc(sizeof(regs)); + if (NULL == spi->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(spi->regs, regs, sizeof(regs)); + spi->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +uint32_t +s3c2410_spi_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_spi_t *spi = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_SPI_BASE; +#endif + if (! S3C2410_OFFSET_OK(spi, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(spi, offset); + +#ifdef DEBUG_S3C2410_SPI + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-spi", S3C2410_SPI_BASE, + reg->name, offset, *(reg->datap)); +#endif + + switch (offset) { + case S3C2410_SPI_SPRDAT0: + spi->spista0 &= ~(1); + break; + + case S3C2410_SPI_SPRDAT1: + spi->spista1 &= ~(1); + break; + } + + return *(reg->datap); +} + +void +s3c2410_spi_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_spi_t *spi = opaque; + x49gp_t *x49gp = spi->x49gp; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_SPI_BASE; +#endif + if (! S3C2410_OFFSET_OK(spi, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(spi, offset); + +#ifdef DEBUG_S3C2410_SPI + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-spi", S3C2410_SPI_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; + + switch (offset) { + case S3C2410_SPI_SPTDAT0: + spi->spista0 |= 1; + s3c2410_intc_assert(x49gp, INT_SPI0, 0); + break; + + case S3C2410_SPI_SPTDAT1: + spi->spista1 |= 1; + s3c2410_intc_assert(x49gp, INT_SPI1, 0); + break; + } +} + +static int +s3c2410_spi_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_spi_t *spi = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < spi->nr_regs; i++) { + reg = &spi->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_spi_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_spi_t *spi = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < spi->nr_regs; i++) { + reg = &spi->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_spi_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_spi_t *spi = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < spi->nr_regs; i++) { + reg = &spi->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_spi_readfn[] = +{ + s3c2410_spi_read, + s3c2410_spi_read, + s3c2410_spi_read +}; + +static CPUWriteMemoryFunc *s3c2410_spi_writefn[] = +{ + s3c2410_spi_write, + s3c2410_spi_write, + s3c2410_spi_write +}; + +static int +s3c2410_spi_init(x49gp_module_t *module) +{ + s3c2410_spi_t *spi; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + spi = malloc(sizeof(s3c2410_spi_t)); + if (NULL == spi) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_spi_data_init(spi)) { + free(spi); + return -ENOMEM; + } + + module->user_data = spi; + spi->x49gp = module->x49gp; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_spi_readfn, + s3c2410_spi_writefn, spi); +#else + iotype = cpu_register_io_memory(s3c2410_spi_readfn, + s3c2410_spi_writefn, spi); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_SPI_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_spi_exit(x49gp_module_t *module) +{ + s3c2410_spi_t *spi; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + spi = module->user_data; + if (spi->regs) + free(spi->regs); + free(spi); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_spi_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-spi", + s3c2410_spi_init, + s3c2410_spi_exit, + s3c2410_spi_reset, + s3c2410_spi_load, + s3c2410_spi_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_sram.c b/s3c2410_sram.c new file mode 100644 index 0000000..5fc2c01 --- /dev/null +++ b/s3c2410_sram.c @@ -0,0 +1,184 @@ +/* $Id: s3c2410_sram.c,v 1.8 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + void *data; + int fd; + uint32_t offset; + size_t size; +} filemap_t; + +static int +s3c2410_sram_load(x49gp_module_t *module, GKeyFile *key) +{ + filemap_t *filemap = module->user_data; + char *filename; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + filename = x49gp_module_get_filename(module, key, "filename"); + if (NULL == filename) { + fprintf(stderr, "%s: %s:%u: key \"filename\" not found\n", + module->name, __FUNCTION__, __LINE__); + return -ENOENT; + } + + filemap->fd = open(filename, O_RDWR); + if (filemap->fd < 0) { + error = -errno; + fprintf(stderr, "%s: %s:%u: open %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + return error; + } + + filemap->data = mmap(phys_ram_base + filemap->offset, S3C2410_SRAM_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + filemap->fd, 0); + if (filemap->data == (void *) -1) { + error = -errno; + fprintf(stderr, "%s: %s:%u: mmap %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + close(filemap->fd); + filemap->fd = -1; + return error; + } + filemap->size = S3C2410_SRAM_SIZE; + + g_free(filename); + + x49gp_schedule_lcd_update(module->x49gp); + return 0; +} + +static int +s3c2410_sram_save(x49gp_module_t *module, GKeyFile *key) +{ + filemap_t *filemap = module->user_data; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + error = msync(filemap->data, filemap->size, MS_ASYNC); + if (error) { + fprintf(stderr, "%s:%u: msync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + error = fsync(filemap->fd); + if (error) { + fprintf(stderr, "%s:%u: fsync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + return 0; +} + +static int +s3c2410_sram_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + return 0; +} + +static int +s3c2410_sram_init(x49gp_module_t *module) +{ + filemap_t *filemap; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + filemap = malloc(sizeof(filemap_t)); + if (NULL == filemap) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + filemap->size = 0; + filemap->fd = -1; + + module->user_data = filemap; + + filemap->data = (void *) -1; + filemap->offset = phys_ram_size; + phys_ram_size += S3C2410_SRAM_SIZE; + + cpu_register_physical_memory(S3C2410_SRAM_BASE, S3C2410_SRAM_SIZE, + filemap->offset | IO_MEM_RAM); + + return 0; +} + +static int +s3c2410_sram_exit(x49gp_module_t *module) +{ + filemap_t *filemap; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + filemap = module->user_data; + + if (filemap->data != (void *) -1) { + munmap(filemap->data, filemap->size); + } + if (filemap->fd >= 0) { + close(filemap->fd); + } + + free(filemap); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_sram_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-sram", + s3c2410_sram_init, + s3c2410_sram_exit, + s3c2410_sram_reset, + s3c2410_sram_load, + s3c2410_sram_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_timer.c b/s3c2410_timer.c new file mode 100644 index 0000000..c0929c5 --- /dev/null +++ b/s3c2410_timer.c @@ -0,0 +1,568 @@ +/* $Id: s3c2410_timer.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +typedef struct { + uint32_t reload_bit; + uint32_t update_bit; + uint32_t start_bit; + unsigned int pre_shift; + unsigned int mux_shift; + int irq; +} s3c2410_timer_config_t; + +struct __s3c2410_timer_s__; +typedef struct __s3c2410_timer_s__ s3c2410_timer_t; + +struct __s3c2410_timer_s__ { + uint32_t tcfg0; + uint32_t tcfg1; + uint32_t tcon; + uint32_t prev_tcon; + + x49gp_t *x49gp; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + struct s3c2410_timeout { + uint32_t tcntb; + uint32_t tcmpb; + uint32_t tcnt; + uint32_t tcmp; + + const s3c2410_timer_config_t *tconfig; + int index; + + s3c2410_timer_t *main; + + unsigned long interval; + x49gp_timer_t *timer; + } timeout[5]; +}; + +static const s3c2410_timer_config_t s3c2410_timer_config[] = +{ + { + TCON_TIMER0_RELOAD, TCON_TIMER0_UPDATE, TCON_TIMER0_START, + TCFG0_PRE0_SHIFT, TCFG1_MUX0_SHIFT, INT_TIMER0 + }, + { + TCON_TIMER1_RELOAD, TCON_TIMER1_UPDATE, TCON_TIMER1_START, + TCFG0_PRE0_SHIFT, TCFG1_MUX1_SHIFT, INT_TIMER1 + }, + { + TCON_TIMER2_RELOAD, TCON_TIMER2_UPDATE, TCON_TIMER2_START, + TCFG0_PRE1_SHIFT, TCFG1_MUX2_SHIFT, INT_TIMER2 + }, + { + TCON_TIMER3_RELOAD, TCON_TIMER3_UPDATE, TCON_TIMER3_START, + TCFG0_PRE1_SHIFT, TCFG1_MUX3_SHIFT, INT_TIMER3 + }, + { + TCON_TIMER4_RELOAD, TCON_TIMER4_UPDATE, TCON_TIMER4_START, + TCFG0_PRE1_SHIFT, TCFG1_MUX4_SHIFT, INT_TIMER4 + }, +}; + +static int +s3c2410_timer_data_init(s3c2410_timer_t *timer) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(TIMER, TCFG0, 0, timer->tcfg0), + S3C2410_OFFSET(TIMER, TCFG1, 0, timer->tcfg1), + S3C2410_OFFSET(TIMER, TCON, 0, timer->tcon), + S3C2410_OFFSET(TIMER, TCNTB0, 0, timer->timeout[0].tcntb), + S3C2410_OFFSET(TIMER, TCMPB0, 0, timer->timeout[0].tcmpb), + S3C2410_OFFSET(TIMER, TCNTO0, 0, timer->timeout[0].tcnt), + S3C2410_OFFSET(TIMER, TCNTB1, 0, timer->timeout[1].tcntb), + S3C2410_OFFSET(TIMER, TCMPB1, 0, timer->timeout[1].tcmpb), + S3C2410_OFFSET(TIMER, TCNTO1, 0, timer->timeout[1].tcnt), + S3C2410_OFFSET(TIMER, TCNTB2, 0, timer->timeout[2].tcntb), + S3C2410_OFFSET(TIMER, TCMPB2, 0, timer->timeout[2].tcmpb), + S3C2410_OFFSET(TIMER, TCNTO2, 0, timer->timeout[2].tcnt), + S3C2410_OFFSET(TIMER, TCNTB3, 0, timer->timeout[3].tcntb), + S3C2410_OFFSET(TIMER, TCMPB3, 0, timer->timeout[3].tcmpb), + S3C2410_OFFSET(TIMER, TCNTO3, 0, timer->timeout[3].tcnt), + S3C2410_OFFSET(TIMER, TCNTB4, 0, timer->timeout[4].tcntb), + S3C2410_OFFSET(TIMER, TCNTO4, 0, timer->timeout[4].tcnt) + }; + + memset(timer, 0, sizeof(s3c2410_timer_t)); + + timer->regs = malloc(sizeof(regs)); + if (NULL == timer->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(timer->regs, regs, sizeof(regs)); + timer->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static void +s3c2410_timer_timeout(void *data) +{ + struct s3c2410_timeout *t = data; + s3c2410_timer_t *timer = t->main; + x49gp_t *x49gp = timer->x49gp; + int64_t timeout; + +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: assert TIMER%u interrupt\n", t->index); +#endif + + s3c2410_intc_assert(timer->x49gp, t->tconfig->irq, 0); + + if (timer->tcon & t->tconfig->reload_bit) { + t->tcnt = t->tcntb; + t->tcmp = t->tcmpb; + } else { + timer->tcon &= ~(t->tconfig->start_bit); + return; + } + + timeout = 1000000LL * t->tcnt * t->interval / x49gp->PCLK; +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: reload TIMER%u: CNT %u (%lu PCLKs): %llu us\n", t->index, t->tcnt, t->interval, timeout); +#endif + x49gp_mod_timer(t->timer, x49gp_get_clock() + timeout); +} + +unsigned long +s3c2410_timer_next_interrupt(x49gp_t *x49gp) +{ + s3c2410_timer_t *timer = x49gp->s3c2410_timer; + struct s3c2410_timeout *t; + unsigned long irq, next; + unsigned long ticks; + int i; + + ticks = x49gp_get_clock(); + + next = ~(0); + for (i = 0; i < 5; i++) { + t = &timer->timeout[i]; + + if (!(timer->tcon & t->tconfig->start_bit)) + continue; + + if (x49gp_timer_pending(t->timer)) { + irq = x49gp_timer_expires(t->timer) - ticks; + } else { + irq = 0; + } + + if (t->tcnt) { + irq += (t->tcnt - 1) * t->interval; + } else { + if (!(timer->tcon & t->tconfig->reload_bit)) + continue; + irq += t->tcntb * t->interval; + } + + if (irq < next) + next = irq; + +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: TIMER%u: tcnt %u, interval %lu, pending %u, next irq %lu\n", + t->index, t->tcnt, t->interval, x49gp_timer_pending(t->timer), irq); +#endif + } + + return next; +} + +static void +s3c2410_update_tcfg(s3c2410_timer_t *timer) +{ + struct s3c2410_timeout *t; + x49gp_t *x49gp = timer->x49gp; + uint32_t pre, mux; + int64_t timeout; + int i; + + for (i = 0; i < 5; i++) { + t = &timer->timeout[i]; + + pre = (timer->tcfg0 >> t->tconfig->pre_shift) & TCFG0_PREx_MASK; + mux = (timer->tcfg1 >> t->tconfig->mux_shift) & TCFG1_MUXx_MASK; + + if (mux > 3) { + printf("s3c2410-timer: can't handle MUX %02x for TIMER%u\n", + mux, t->index); + mux = 3; + } + + t->interval = (pre + 1) * (2 << mux); + +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: TIMER%u: pre %u, mux %u, tick %lu PCLKs\n", + t->index, pre, mux, t->interval); +#endif + if (x49gp_timer_pending(t->timer)) { + timeout = 1000000LL * t->tcnt * t->interval / x49gp->PCLK; +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: mod TIMER%u: CNT %u (%lu PCLKs): %llu us\n", t->index, t->tcnt, t->interval, timeout); +#endif + x49gp_mod_timer(t->timer, x49gp_get_clock() + timeout); + } + } +} + +static void +s3c2410_update_tcon(s3c2410_timer_t *timer) +{ + struct s3c2410_timeout *t; + x49gp_t *x49gp = timer->x49gp; + int64_t timeout; + uint32_t change; + int i; + + change = timer->prev_tcon ^ timer->tcon; + timer->prev_tcon = timer->tcon; + + for (i = 0; i < 5; i++) { + t = &timer->timeout[i]; + + if (timer->tcon & t->tconfig->update_bit) { + t->tcnt = t->tcntb; + t->tcmp = t->tcmpb; + +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: update TIMER%u tcnt %u, tcmp %u\n", t->index, t->tcnt, t->tcmp); +#endif + } + + if (change & t->tconfig->start_bit) { + if (timer->tcon & t->tconfig->start_bit) { + timeout = 1000000LL * t->tcnt * t->interval / x49gp->PCLK; +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: start TIMER%u: CNT %u (%lu PCLKs): %llu us\n", t->index, t->tcnt, t->interval, timeout); +#endif + x49gp_mod_timer(t->timer, x49gp_get_clock() + timeout); + } else { + x49gp_del_timer(t->timer); +#ifdef DEBUG_S3C2410_TIMER + printf("s3c2410-timer: stop TIMER%u\n", t->index); +#endif + } + } + } +} + +static uint32_t +s3c2410_read_tcnt(s3c2410_timer_t *timer, int index) +{ + struct s3c2410_timeout *t = &timer->timeout[index]; + x49gp_t *x49gp = timer->x49gp; + int64_t now, expires, timeout; + + if (!(timer->tcon & t->tconfig->start_bit)) + return t->tcnt; + + if (x49gp_timer_pending(t->timer)) { + now = x49gp_get_clock(); + expires = x49gp_timer_expires(t->timer); + + timeout = expires - now; + if (timeout <= 0) + return 0; + + t->tcnt = timeout * x49gp->PCLK / (1000000LL * t->interval); + } + + return t->tcnt; +} + +static uint32_t +s3c2410_timer_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_timer_t *timer = opaque; + s3c2410_offset_t *reg; + uint32_t data; + +#ifdef QEMU_OLD + offset -= S3C2410_TIMER_BASE; +#endif + if (! S3C2410_OFFSET_OK(timer, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(timer, offset); + + switch (offset) { + case S3C2410_TIMER_TCNTO0: + data = s3c2410_read_tcnt(timer, 0); + break; + case S3C2410_TIMER_TCNTO1: + data = s3c2410_read_tcnt(timer, 1); + break; + case S3C2410_TIMER_TCNTO2: + data = s3c2410_read_tcnt(timer, 2); + break; + case S3C2410_TIMER_TCNTO3: + data = s3c2410_read_tcnt(timer, 3); + break; + case S3C2410_TIMER_TCNTO4: + data = s3c2410_read_tcnt(timer, 4); + break; + default: + data = *(reg->datap); + break; + } + +#ifdef DEBUG_S3C2410_TIMER + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-timer", S3C2410_TIMER_BASE, + reg->name, offset, data); +#endif + + return data; +} + +static void +s3c2410_timer_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_timer_t *timer = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_TIMER_BASE; +#endif + if (! S3C2410_OFFSET_OK(timer, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(timer, offset); + +#ifdef DEBUG_S3C2410_TIMER + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-timer", S3C2410_TIMER_BASE, + reg->name, offset, data); +#endif + + switch (offset) { + case S3C2410_TIMER_TCFG0: + *(reg->datap) = data; + s3c2410_update_tcfg(timer); + break; + case S3C2410_TIMER_TCFG1: + *(reg->datap) = data; + s3c2410_update_tcfg(timer); + break; + case S3C2410_TIMER_TCON: + *(reg->datap) = data; + s3c2410_update_tcon(timer); + break; + case S3C2410_TIMER_TCNTO0: + case S3C2410_TIMER_TCNTO1: + case S3C2410_TIMER_TCNTO2: + case S3C2410_TIMER_TCNTO3: + case S3C2410_TIMER_TCNTO4: + /* read only */ + break; + default: + *(reg->datap) = data; + break; + } +} + +static int +s3c2410_timer_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_timer_t *timer = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < timer->nr_regs; i++) { + reg = &timer->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + s3c2410_update_tcon(timer); + s3c2410_update_tcfg(timer); + + return error; +} + +static int +s3c2410_timer_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_timer_t *timer = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < timer->nr_regs; i++) { + reg = &timer->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_timer_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_timer_t *timer = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < timer->nr_regs; i++) { + reg = &timer->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + s3c2410_update_tcon(timer); + s3c2410_update_tcfg(timer); + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_timer_readfn[] = +{ + s3c2410_timer_read, + s3c2410_timer_read, + s3c2410_timer_read +}; + +static CPUWriteMemoryFunc *s3c2410_timer_writefn[] = +{ + s3c2410_timer_write, + s3c2410_timer_write, + s3c2410_timer_write +}; + +static int +s3c2410_timer_init(x49gp_module_t *module) +{ + s3c2410_timer_t *timer; + struct s3c2410_timeout *t; + int iotype; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + timer = malloc(sizeof(s3c2410_timer_t)); + if (NULL == timer) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->x49gp->progname, __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_timer_data_init(timer)) { + free(timer); + return -ENOMEM; + } + + module->user_data = timer; + + timer->x49gp = module->x49gp; + module->x49gp->s3c2410_timer = timer; + + for (i = 0; i < 5; i++) { + t = &timer->timeout[i]; + + t->tconfig = &s3c2410_timer_config[i]; + t->index = i; + + t->main = timer; + + t->timer = x49gp_new_timer(X49GP_TIMER_VIRTUAL, s3c2410_timer_timeout, t); + } + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_timer_readfn, + s3c2410_timer_writefn, timer); +#else + iotype = cpu_register_io_memory(s3c2410_timer_readfn, + s3c2410_timer_writefn, timer); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_TIMER_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_timer_exit(x49gp_module_t *module) +{ + s3c2410_timer_t *timer; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + timer = module->user_data; + if (timer->regs) + free(timer->regs); + free(timer); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_timer_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-timer", + s3c2410_timer_init, + s3c2410_timer_exit, + s3c2410_timer_reset, + s3c2410_timer_load, + s3c2410_timer_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_uart.c b/s3c2410_uart.c new file mode 100644 index 0000000..d743b47 --- /dev/null +++ b/s3c2410_uart.c @@ -0,0 +1,484 @@ +/* $Id: s3c2410_uart.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct { + uint32_t ulcon; + uint32_t ucon; + uint32_t ufcon; + uint32_t umcon; + uint32_t utrstat; + uint32_t uerstat; + uint32_t ufstat; + uint32_t umstat; + uint32_t utxh; + uint32_t urxh; + uint32_t ubrdiv; + + int int_err; + int int_txd; + int int_rxd; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; +} s3c2410_uart_reg_t; + +typedef struct { + s3c2410_uart_reg_t uart[3]; +} s3c2410_uart_t; + +static int +s3c2410_uart_data_init(s3c2410_uart_t *uart) +{ + s3c2410_offset_t regs0[] = { + S3C2410_OFFSET(UART0, ULCON, 0x00000000, uart->uart[0].ulcon), + S3C2410_OFFSET(UART0, UCON, 0x00000000, uart->uart[0].ucon), + S3C2410_OFFSET(UART0, UFCON, 0x00000000, uart->uart[0].ufcon), + S3C2410_OFFSET(UART0, UMCON, 0x00000000, uart->uart[0].umcon), + S3C2410_OFFSET(UART0, UTRSTAT, 0x00000006, uart->uart[0].utrstat), + S3C2410_OFFSET(UART0, UERSTAT, 0x00000000, uart->uart[0].uerstat), + S3C2410_OFFSET(UART0, UFSTAT, 0x00000000, uart->uart[0].ufstat), + S3C2410_OFFSET(UART0, UMSTAT, 0x00000000, uart->uart[0].umstat), + S3C2410_OFFSET(UART0, UTXH, 0, uart->uart[0].utxh), + S3C2410_OFFSET(UART0, URXH, 0, uart->uart[0].urxh), + S3C2410_OFFSET(UART0, UBRDIV, 0, uart->uart[0].ubrdiv) + }; + s3c2410_offset_t regs1[] = { + S3C2410_OFFSET(UART1, ULCON, 0x00000000, uart->uart[1].ulcon), + S3C2410_OFFSET(UART1, UCON, 0x00000000, uart->uart[1].ucon), + S3C2410_OFFSET(UART1, UFCON, 0x00000000, uart->uart[1].ufcon), + S3C2410_OFFSET(UART1, UMCON, 0x00000000, uart->uart[1].umcon), + S3C2410_OFFSET(UART1, UTRSTAT, 0x00000006, uart->uart[1].utrstat), + S3C2410_OFFSET(UART1, UERSTAT, 0x00000000, uart->uart[1].uerstat), + S3C2410_OFFSET(UART1, UFSTAT, 0x00000000, uart->uart[1].ufstat), + S3C2410_OFFSET(UART1, UMSTAT, 0x00000000, uart->uart[1].umstat), + S3C2410_OFFSET(UART1, UTXH, 0, uart->uart[1].utxh), + S3C2410_OFFSET(UART1, URXH, 0, uart->uart[1].urxh), + S3C2410_OFFSET(UART1, UBRDIV, 0, uart->uart[1].ubrdiv) + }; + s3c2410_offset_t regs2[] = { + S3C2410_OFFSET(UART2, ULCON, 0x00000000, uart->uart[2].ulcon), + S3C2410_OFFSET(UART2, UCON, 0x00000000, uart->uart[2].ucon), + S3C2410_OFFSET(UART2, UFCON, 0x00000000, uart->uart[2].ufcon), + S3C2410_OFFSET(UART2, UTRSTAT, 0x00000006, uart->uart[2].utrstat), + S3C2410_OFFSET(UART2, UERSTAT, 0x00000000, uart->uart[2].uerstat), + S3C2410_OFFSET(UART2, UFSTAT, 0x00000000, uart->uart[2].ufstat), + S3C2410_OFFSET(UART2, UTXH, 0, uart->uart[2].utxh), + S3C2410_OFFSET(UART2, URXH, 0, uart->uart[2].urxh), + S3C2410_OFFSET(UART2, UBRDIV, 0, uart->uart[2].ubrdiv) + }; + + uart->uart[0].regs = malloc(sizeof(regs0)); + if (NULL == uart->uart[0].regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + uart->uart[1].regs = malloc(sizeof(regs1)); + if (NULL == uart->uart[1].regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + free(uart->uart[0].regs); + return -ENOMEM; + } + uart->uart[2].regs = malloc(sizeof(regs2)); + if (NULL == uart->uart[2].regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + free(uart->uart[0].regs); + free(uart->uart[1].regs); + return -ENOMEM; + } + + memcpy(uart->uart[0].regs, regs0, sizeof(regs0)); + uart->uart[0].nr_regs = sizeof(regs0) / sizeof(regs0[0]); + uart->uart[0].int_err = SUB_INT_ERR0; + uart->uart[0].int_txd = SUB_INT_TXD0; + uart->uart[0].int_rxd = SUB_INT_RXD0; + + memcpy(uart->uart[1].regs, regs1, sizeof(regs1)); + uart->uart[1].nr_regs = sizeof(regs1) / sizeof(regs1[0]); + uart->uart[1].int_err = SUB_INT_ERR1; + uart->uart[1].int_txd = SUB_INT_TXD1; + uart->uart[1].int_rxd = SUB_INT_RXD1; + + memcpy(uart->uart[2].regs, regs2, sizeof(regs2)); + uart->uart[2].nr_regs = sizeof(regs2) / sizeof(regs2[0]); + uart->uart[2].int_err = SUB_INT_ERR2; + uart->uart[2].int_txd = SUB_INT_TXD2; + uart->uart[2].int_rxd = SUB_INT_RXD2; + + return 0; +} + +static uint32_t +s3c2410_uart_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_uart_reg_t *uart_regs = opaque; + x49gp_t *x49gp = uart_regs->x49gp; + s3c2410_offset_t *reg; +#ifdef DEBUG_S3C2410_UART + const char *module; + uint32_t mod_offset; + uint32_t base; + + base = (offset & 0x0000c000) >> 14; + + switch (base) { + case 0: + module = "s3c2410-uart0"; + mod_offset = S3C2410_UART0_BASE; + break; + case 1: + module = "s3c2410-uart1"; + mod_offset = S3C2410_UART1_BASE; + break; + case 2: + module = "s3c2410-uart2"; + mod_offset = S3C2410_UART2_BASE; + break; + default: + return ~(0); + } +#endif + + offset &= ~(0xffffc000); + if (! S3C2410_OFFSET_OK(uart_regs, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(uart_regs, offset); + +#ifdef DEBUG_S3C2410_UART + printf("read %s [%08x] %s [%08x] data %08x\n", + module, base, reg->name, offset, *(reg->datap)); +#endif + + switch (offset) { + case S3C2410_UART0_URXH: + uart_regs->utrstat &= ~(1 << 0); + + if (uart_regs->ucon & (1 << 8)) { + s3c2410_intc_sub_deassert(x49gp, uart_regs->int_rxd); + } + + break; + } + + return *(reg->datap); +} + +static void +s3c2410_uart_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_uart_reg_t *uart_regs = opaque; + x49gp_t *x49gp = uart_regs->x49gp; + s3c2410_offset_t *reg; + uint32_t ubrdivn, baud; + uint32_t base; +#ifdef DEBUG_S3C2410_UART + const char *module; + uint32_t mod_offset; +#endif + + base = (offset & 0x0000c000) >> 14; + +#ifdef DEBUG_S3C2410_UART + switch (base) { + case 0: + module = "s3c2410-uart0"; + mod_offset = S3C2410_UART0_BASE; + break; + case 1: + module = "s3c2410-uart1"; + mod_offset = S3C2410_UART1_BASE; + break; + case 2: + module = "s3c2410-uart2"; + mod_offset = S3C2410_UART2_BASE; + break; + default: + return; + } +#endif + + offset &= ~(0xffffc000); + if (! S3C2410_OFFSET_OK(uart_regs, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(uart_regs, offset); + +#ifdef DEBUG_S3C2410_UART + printf("write %s [%08x] %s [%08x] data %08x\n", + module, mod_offset, reg->name, offset, data); +#endif + + *(reg->datap) = data; + + switch (offset) { + case S3C2410_UART0_UCON: + if (*(reg->datap) & (1 << 9)) + s3c2410_intc_sub_assert(x49gp, uart_regs->int_txd, 1); + if (*(reg->datap) & (1 << 8)) + s3c2410_intc_sub_deassert(x49gp, uart_regs->int_rxd); + break; + + case S3C2410_UART0_UBRDIV: + ubrdivn = (data >> 0) & 0xffff; + if (uart_regs->ucon & (1 << 10)) { + baud = x49gp->UCLK / 16 / (ubrdivn + 1); +#ifdef DEBUG_S3C2410_UART + printf("%s: UEXTCLK %u, ubrdivn %u, baud %u\n", + module, x49gp->UCLK, ubrdivn, baud); +#endif + } else { + baud = x49gp->PCLK / 16 / (ubrdivn + 1); +#ifdef DEBUG_S3C2410_UART + printf("%s: PCLK %u, ubrdivn %u, baud %u\n", + module, x49gp->PCLK, ubrdivn, baud); +#endif + } + break; + + case S3C2410_UART0_UTXH: + if (uart_regs->ucon & (1 << 9)) + s3c2410_intc_sub_deassert(x49gp, uart_regs->int_txd); + + uart_regs->utrstat |= (1 << 2) | (1 << 1); + + if (uart_regs->ucon & (1 << 9)) + s3c2410_intc_sub_assert(x49gp, uart_regs->int_txd, 1); + else + s3c2410_intc_sub_assert(x49gp, uart_regs->int_txd, 0); + + if (uart_regs->ucon & (1 << 5)) { + uart_regs->urxh = data; + uart_regs->utrstat |= (1 << 0); + + if (uart_regs->ucon & (1 << 8)) + s3c2410_intc_sub_assert(x49gp, uart_regs->int_rxd, 1); + else + s3c2410_intc_sub_assert(x49gp, uart_regs->int_rxd, 0); + } else if (base == 2) { + uart_regs->urxh = data; + uart_regs->utrstat |= (1 << 0); + + if (uart_regs->ucon & (1 << 8)) + s3c2410_intc_sub_assert(x49gp, uart_regs->int_rxd, 1); + else + s3c2410_intc_sub_assert(x49gp, uart_regs->int_rxd, 0); + } + + break; + } +} + +static int +s3c2410_uart_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_uart_reg_t *uart_regs = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < uart_regs->nr_regs; i++) { + reg = &uart_regs->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_uart_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_uart_reg_t *uart_regs = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < uart_regs->nr_regs; i++) { + reg = &uart_regs->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_uart_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_uart_reg_t *uart_regs = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < uart_regs->nr_regs; i++) { + reg = &uart_regs->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_uart_readfn[] = +{ + s3c2410_uart_read, + s3c2410_uart_read, + s3c2410_uart_read +}; + +static CPUWriteMemoryFunc *s3c2410_uart_writefn[] = +{ + s3c2410_uart_write, + s3c2410_uart_write, + s3c2410_uart_write +}; + +static int +s3c2410_uart_init(x49gp_module_t *module) +{ + s3c2410_uart_reg_t *uart_regs = module->user_data; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_uart_readfn, + s3c2410_uart_writefn, uart_regs); +#else + iotype = cpu_register_io_memory(s3c2410_uart_readfn, + s3c2410_uart_writefn, uart_regs); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_UART0_BASE, S3C2410_MAP_SIZE, iotype); + + return 0; +} + +static int +s3c2410_uart_exit(x49gp_module_t *module) +{ + s3c2410_uart_reg_t *uart_regs; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + uart_regs = module->user_data; + if (uart_regs->regs) + free(uart_regs->regs); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_uart_init(x49gp_t *x49gp) +{ + s3c2410_uart_t *uart; + x49gp_module_t *module; + + uart = malloc(sizeof(s3c2410_uart_t)); + if (NULL == uart) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + memset(uart, 0, sizeof(s3c2410_uart_t)); + + if (s3c2410_uart_data_init(uart)) { + free(uart); + return -ENOMEM; + } + + uart->uart[0].x49gp = x49gp; + uart->uart[1].x49gp = x49gp; + uart->uart[2].x49gp = x49gp; + + if (x49gp_module_init(x49gp, "s3c2410-uart0", + s3c2410_uart_init, + s3c2410_uart_exit, + s3c2410_uart_reset, + s3c2410_uart_load, + s3c2410_uart_save, + &uart->uart[0], &module)) { + return -1; + } + if (x49gp_module_register(module)) { + return -1; + } + + if (x49gp_module_init(x49gp, "s3c2410-uart1", + s3c2410_uart_init, + s3c2410_uart_exit, + s3c2410_uart_reset, + s3c2410_uart_load, + s3c2410_uart_save, + &uart->uart[1], &module)) { + return -1; + } + if (x49gp_module_register(module)) { + return -1; + } + + if (x49gp_module_init(x49gp, "s3c2410-uart2", + s3c2410_uart_init, + s3c2410_uart_exit, + s3c2410_uart_reset, + s3c2410_uart_load, + s3c2410_uart_save, + &uart->uart[2], &module)) { + return -1; + } + if (x49gp_module_register(module)) { + return -1; + } + + return 0; +} diff --git a/s3c2410_usbdev.c b/s3c2410_usbdev.c new file mode 100644 index 0000000..580e7a1 --- /dev/null +++ b/s3c2410_usbdev.c @@ -0,0 +1,342 @@ +/* $Id: s3c2410_usbdev.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef struct { + uint32_t func_addr_reg; + uint32_t pwr_reg; + uint32_t ep_int_reg; + uint32_t usb_int_reg; + uint32_t ep_int_en_reg; + uint32_t usb_int_en_reg; + uint32_t frame_num1_reg; + uint32_t frame_num2_reg; + uint32_t index_reg; + uint32_t ep0_fifo_reg; + uint32_t ep1_fifo_reg; + uint32_t ep2_fifo_reg; + uint32_t ep3_fifo_reg; + uint32_t ep4_fifo_reg; + uint32_t ep1_dma_con; + uint32_t ep1_dma_unit; + uint32_t ep1_dma_fifo; + uint32_t ep1_dma_ttc_l; + uint32_t ep1_dma_ttc_m; + uint32_t ep1_dma_ttc_h; + uint32_t ep2_dma_con; + uint32_t ep2_dma_unit; + uint32_t ep2_dma_fifo; + uint32_t ep2_dma_ttc_l; + uint32_t ep2_dma_ttc_m; + uint32_t ep2_dma_ttc_h; + uint32_t ep3_dma_con; + uint32_t ep3_dma_unit; + uint32_t ep3_dma_fifo; + uint32_t ep3_dma_ttc_l; + uint32_t ep3_dma_ttc_m; + uint32_t ep3_dma_ttc_h; + uint32_t ep4_dma_con; + uint32_t ep4_dma_unit; + uint32_t ep4_dma_fifo; + uint32_t ep4_dma_ttc_l; + uint32_t ep4_dma_ttc_m; + uint32_t ep4_dma_ttc_h; + uint32_t __wrong_maxp_reg; + uint32_t in_csr1_reg_ep0_csr; + uint32_t in_csr2_reg; + uint32_t maxp_reg; + uint32_t out_csr1_reg; + uint32_t out_csr2_reg; + uint32_t out_fifo_cnt1_reg; + uint32_t out_fifo_cnt2_reg; + + unsigned int nr_regs; + s3c2410_offset_t *regs; +} s3c2410_usbdev_t; + +static int +s3c2410_usbdev_data_init(s3c2410_usbdev_t *usbdev) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(USBDEV, FUNC_ADDR_REG, 0x00, usbdev->func_addr_reg), + S3C2410_OFFSET(USBDEV, PWR_REG, 0x00, usbdev->pwr_reg), + S3C2410_OFFSET(USBDEV, EP_INT_REG, 0x00, usbdev->ep_int_reg), + S3C2410_OFFSET(USBDEV, USB_INT_REG, 0x00, usbdev->usb_int_reg), + S3C2410_OFFSET(USBDEV, EP_INT_EN_REG, 0xff, usbdev->ep_int_en_reg), + S3C2410_OFFSET(USBDEV, USB_INT_EN_REG, 0x04, usbdev->usb_int_en_reg), + S3C2410_OFFSET(USBDEV, FRAME_NUM1_REG, 0x00, usbdev->frame_num1_reg), + S3C2410_OFFSET(USBDEV, FRAME_NUM2_REG, 0x00, usbdev->frame_num2_reg), + S3C2410_OFFSET(USBDEV, INDEX_REG, 0x00, usbdev->index_reg), + S3C2410_OFFSET(USBDEV, EP0_FIFO_REG, 0, usbdev->ep0_fifo_reg), + S3C2410_OFFSET(USBDEV, EP1_FIFO_REG, 0, usbdev->ep1_fifo_reg), + S3C2410_OFFSET(USBDEV, EP2_FIFO_REG, 0, usbdev->ep2_fifo_reg), + S3C2410_OFFSET(USBDEV, EP3_FIFO_REG, 0, usbdev->ep3_fifo_reg), + S3C2410_OFFSET(USBDEV, EP4_FIFO_REG, 0, usbdev->ep4_fifo_reg), + S3C2410_OFFSET(USBDEV, EP1_DMA_CON, 0x00, usbdev->ep1_dma_con), + S3C2410_OFFSET(USBDEV, EP1_DMA_UNIT, 0x00, usbdev->ep1_dma_unit), + S3C2410_OFFSET(USBDEV, EP1_DMA_FIFO, 0x00, usbdev->ep1_dma_fifo), + S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_L, 0x00, usbdev->ep1_dma_ttc_l), + S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_M, 0x00, usbdev->ep1_dma_ttc_m), + S3C2410_OFFSET(USBDEV, EP1_DMA_TTC_H, 0x00, usbdev->ep1_dma_ttc_h), + S3C2410_OFFSET(USBDEV, EP2_DMA_CON, 0x00, usbdev->ep2_dma_con), + S3C2410_OFFSET(USBDEV, EP2_DMA_UNIT, 0x00, usbdev->ep2_dma_unit), + S3C2410_OFFSET(USBDEV, EP2_DMA_FIFO, 0x00, usbdev->ep2_dma_fifo), + S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_L, 0x00, usbdev->ep2_dma_ttc_l), + S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_M, 0x00, usbdev->ep2_dma_ttc_m), + S3C2410_OFFSET(USBDEV, EP2_DMA_TTC_H, 0x00, usbdev->ep2_dma_ttc_h), + S3C2410_OFFSET(USBDEV, EP3_DMA_CON, 0x00, usbdev->ep3_dma_con), + S3C2410_OFFSET(USBDEV, EP3_DMA_UNIT, 0x00, usbdev->ep3_dma_unit), + S3C2410_OFFSET(USBDEV, EP3_DMA_FIFO, 0x00, usbdev->ep3_dma_fifo), + S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_L, 0x00, usbdev->ep3_dma_ttc_l), + S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_M, 0x00, usbdev->ep3_dma_ttc_m), + S3C2410_OFFSET(USBDEV, EP3_DMA_TTC_H, 0x00, usbdev->ep3_dma_ttc_h), + S3C2410_OFFSET(USBDEV, EP4_DMA_CON, 0x00, usbdev->ep4_dma_con), + S3C2410_OFFSET(USBDEV, EP4_DMA_UNIT, 0x00, usbdev->ep4_dma_unit), + S3C2410_OFFSET(USBDEV, EP4_DMA_FIFO, 0x00, usbdev->ep4_dma_fifo), + S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_L, 0x00, usbdev->ep4_dma_ttc_l), + S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_M, 0x00, usbdev->ep4_dma_ttc_m), + S3C2410_OFFSET(USBDEV, EP4_DMA_TTC_H, 0x00, usbdev->ep4_dma_ttc_h), + S3C2410_OFFSET(USBDEV, MAXP_REG_WRONG, 0x01, usbdev->__wrong_maxp_reg), + S3C2410_OFFSET(USBDEV, IN_CSR1_REG_EP0_CSR, 0x00, usbdev->in_csr1_reg_ep0_csr), + S3C2410_OFFSET(USBDEV, IN_CSR2_REG, 0x20, usbdev->in_csr2_reg), + S3C2410_OFFSET(USBDEV, MAXP_REG, 0x01, usbdev->maxp_reg), + S3C2410_OFFSET(USBDEV, OUT_CSR1_REG, 0x00, usbdev->out_csr1_reg), + S3C2410_OFFSET(USBDEV, OUT_CSR2_REG, 0x00, usbdev->out_csr2_reg), + S3C2410_OFFSET(USBDEV, OUT_FIFO_CNT1_REG, 0x00, usbdev->out_fifo_cnt1_reg), + S3C2410_OFFSET(USBDEV, OUT_FIFO_CNT2_REG, 0x00, usbdev->out_fifo_cnt2_reg) + }; + + memset(usbdev, 0, sizeof(s3c2410_usbdev_t)); + + usbdev->regs = malloc(sizeof(regs)); + if (NULL == usbdev->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(usbdev->regs, regs, sizeof(regs)); + usbdev->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static uint32_t +s3c2410_usbdev_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_usbdev_t *usbdev = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_USBDEV_BASE; +#endif + if (! S3C2410_OFFSET_OK(usbdev, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(usbdev, offset); + +#ifdef DEBUG_S3C2410_USBDEV + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-usbdev", S3C2410_USBDEV_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_usbdev_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_usbdev_t *usbdev = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_USBDEV_BASE; +#endif + if (! S3C2410_OFFSET_OK(usbdev, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(usbdev, offset); + +#ifdef DEBUG_S3C2410_USBDEV + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-usbdev", S3C2410_USBDEV_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; +} + +static int +s3c2410_usbdev_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_usbdev_t *usbdev = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < usbdev->nr_regs; i++) { + reg = &usbdev->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + return error; +} + +static int +s3c2410_usbdev_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_usbdev_t *usbdev = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < usbdev->nr_regs; i++) { + reg = &usbdev->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_usbdev_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_usbdev_t *usbdev = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < usbdev->nr_regs; i++) { + reg = &usbdev->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_usbdev_readfn[] = +{ + s3c2410_usbdev_read, + s3c2410_usbdev_read, + s3c2410_usbdev_read +}; + +static CPUWriteMemoryFunc *s3c2410_usbdev_writefn[] = +{ + s3c2410_usbdev_write, + s3c2410_usbdev_write, + s3c2410_usbdev_write +}; + +static int +s3c2410_usbdev_init(x49gp_module_t *module) +{ + s3c2410_usbdev_t *usbdev; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + usbdev = malloc(sizeof(s3c2410_usbdev_t)); + if (NULL == usbdev) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_usbdev_data_init(usbdev)) { + free(usbdev); + return -ENOMEM; + } + + module->user_data = usbdev; + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_usbdev_readfn, + s3c2410_usbdev_writefn, usbdev); +#else + iotype = cpu_register_io_memory(s3c2410_usbdev_readfn, + s3c2410_usbdev_writefn, usbdev); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_USBDEV_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_usbdev_exit(x49gp_module_t *module) +{ + s3c2410_usbdev_t *usbdev; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + usbdev = module->user_data; + if (usbdev->regs) + free(usbdev->regs); + free(usbdev); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_usbdev_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-usbdev", + s3c2410_usbdev_init, + s3c2410_usbdev_exit, + s3c2410_usbdev_reset, + s3c2410_usbdev_load, + s3c2410_usbdev_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/s3c2410_watchdog.c b/s3c2410_watchdog.c new file mode 100644 index 0000000..d69acf2 --- /dev/null +++ b/s3c2410_watchdog.c @@ -0,0 +1,388 @@ +/* $Id: s3c2410_watchdog.c,v 1.5 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct { + uint32_t wtcon; + uint32_t wtdat; + uint32_t wtcnt; + + unsigned int nr_regs; + s3c2410_offset_t *regs; + + x49gp_t *x49gp; + + unsigned long interval; + x49gp_timer_t *timer; +} s3c2410_watchdog_t; + +static int +s3c2410_watchdog_data_init(s3c2410_watchdog_t *watchdog) +{ + s3c2410_offset_t regs[] = { + S3C2410_OFFSET(WATCHDOG, WTCON, 0x8021, watchdog->wtcon), + S3C2410_OFFSET(WATCHDOG, WTDAT, 0x8000, watchdog->wtdat), + S3C2410_OFFSET(WATCHDOG, WTCNT, 0x8000, watchdog->wtcnt) + }; + + memset(watchdog, 0, sizeof(s3c2410_watchdog_t)); + + watchdog->regs = malloc(sizeof(regs)); + if (NULL == watchdog->regs) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + + memcpy(watchdog->regs, regs, sizeof(regs)); + watchdog->nr_regs = sizeof(regs) / sizeof(regs[0]); + + return 0; +} + +static void +s3c2410_watchdog_tick(void *data) +{ + s3c2410_watchdog_t *watchdog = data; + x49gp_t *x49gp = watchdog->x49gp; + + if (watchdog->wtcnt > 0) { + watchdog->wtcnt--; + } else { + watchdog->wtcnt = watchdog->wtdat; + } + + if (watchdog->wtcnt > 0) { +// watchdog->timer.expires += watchdog->interval; + x49gp_mod_timer(watchdog->timer, x49gp_get_clock() + watchdog->interval); + return; + } + + if (watchdog->wtcon & 0x0004) { +#ifdef DEBUG_S3C2410_WATCHDOG + printf("WATCHDOG: assert WDT interrupt\n"); +#endif +// g_mutex_lock(x49gp->memlock); + + s3c2410_intc_assert(x49gp, INT_WDT, 0); + +// g_mutex_unlock(x49gp->memlock); + } + + if (watchdog->wtcon & 0x0001) { +#ifdef DEBUG_S3C2410_WATCHDOG + printf("WATCHDOG: assert internal RESET\n"); +#endif + + x49gp_modules_reset(x49gp, X49GP_RESET_WATCHDOG); + cpu_reset(x49gp->env); + +// if (x49gp->arm->NresetSig != LOW) { +// x49gp->arm->NresetSig = LOW; +// x49gp->arm->Exception++; +// } + return; + } + +// watchdog->timer.expires += watchdog->interval; + x49gp_mod_timer(watchdog->timer, x49gp_get_clock() + watchdog->interval); +} + +unsigned long +s3c2410_watchdog_next_interrupt(x49gp_t *x49gp) +{ + s3c2410_watchdog_t *watchdog = x49gp->s3c2410_watchdog; + unsigned long irq; + unsigned long ticks; + + ticks = x49gp_get_clock(); + + if (!(watchdog->wtcon & 0x0020)) { + return ~(0); + } + + if (x49gp_timer_pending(watchdog->timer)) { + irq = x49gp_timer_expires(watchdog->timer) - ticks; + } else { + irq = 0; + } + + if (watchdog->wtcnt) { + irq += (watchdog->wtcnt - 1) * watchdog->interval; + } else { + irq += watchdog->wtdat * watchdog->interval; + } + +#ifdef DEBUG_S3C2410_WATCHDOG + printf("WATCHDOG: wtcnt %u, interval %lu, expires %llu, next irq %lu\n", + watchdog->wtcnt, watchdog->interval, x49gp_timer_pending(watchdog->timer) ? x49gp_timer_expires(watchdog->timer) : 0, irq); +#endif + + return irq; +} + +static int +s3c2410_watchdog_update(s3c2410_watchdog_t *watchdog) +{ + uint32_t pre, mux; + + if (!(watchdog->wtcon & 0x0020)) { + x49gp_del_timer(watchdog->timer); +#ifdef DEBUG_S3C2410_WATCHDOG + printf("WATCHDOG: stop timer\n"); +#endif + return 0; + } + + pre = (watchdog->wtcon >> 8) & 0xff; + mux = (watchdog->wtcon >> 3) & 3; + + watchdog->interval = (pre + 1) * (16 << mux); + +#ifdef DEBUG_S3C2410_WATCHDOG + printf("WATCHDOG: start tick (%lu PCLKs)\n", watchdog->interval); +#endif + x49gp_mod_timer(watchdog->timer, x49gp_get_clock() + watchdog->interval); + return 0; +} + +static uint32_t +s3c2410_watchdog_read(void *opaque, target_phys_addr_t offset) +{ + s3c2410_watchdog_t *watchdog = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_WATCHDOG_BASE; +#endif + if (! S3C2410_OFFSET_OK(watchdog, offset)) { + return ~(0); + } + + reg = S3C2410_OFFSET_ENTRY(watchdog, offset); + + +#ifdef DEBUG_S3C2410_WATCHDOG + printf("read %s [%08x] %s [%08x] data %08x\n", + "s3c2410-watchdog", S3C2410_WATCHDOG_BASE, + reg->name, offset, *(reg->datap)); +#endif + + return *(reg->datap); +} + +static void +s3c2410_watchdog_write(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + s3c2410_watchdog_t *watchdog = opaque; + s3c2410_offset_t *reg; + +#ifdef QEMU_OLD + offset -= S3C2410_WATCHDOG_BASE; +#endif + if (! S3C2410_OFFSET_OK(watchdog, offset)) { + return; + } + + reg = S3C2410_OFFSET_ENTRY(watchdog, offset); + +#ifdef DEBUG_S3C2410_WATCHDOG + printf("write %s [%08x] %s [%08x] data %08x\n", + "s3c2410-watchdog", S3C2410_WATCHDOG_BASE, + reg->name, offset, data); +#endif + + *(reg->datap) = data; + + switch (offset) { + case S3C2410_WATCHDOG_WTCON: + case S3C2410_WATCHDOG_WTCNT: + s3c2410_watchdog_update(watchdog); + break; + default: + break; + } +} + +static int +s3c2410_watchdog_load(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_watchdog_t *watchdog = module->user_data; + s3c2410_offset_t *reg; + int error = 0; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < watchdog->nr_regs; i++) { + reg = &watchdog->regs[i]; + + if (NULL == reg->name) + continue; + + if (x49gp_module_get_u32(module, key, reg->name, + reg->reset, reg->datap)) + error = -EAGAIN; + } + + s3c2410_watchdog_update(watchdog); + + return error; +} + +static int +s3c2410_watchdog_save(x49gp_module_t *module, GKeyFile *key) +{ + s3c2410_watchdog_t *watchdog = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < watchdog->nr_regs; i++) { + reg = &watchdog->regs[i]; + + if (NULL == reg->name) + continue; + + x49gp_module_set_u32(module, key, reg->name, *(reg->datap)); + } + + return 0; +} + +static int +s3c2410_watchdog_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + s3c2410_watchdog_t *watchdog = module->user_data; + s3c2410_offset_t *reg; + int i; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + for (i = 0; i < watchdog->nr_regs; i++) { + reg = &watchdog->regs[i]; + + if (NULL == reg->name) + continue; + + *(reg->datap) = reg->reset; + } + + s3c2410_watchdog_update(watchdog); + + return 0; +} + +static CPUReadMemoryFunc *s3c2410_watchdog_readfn[] = +{ + s3c2410_watchdog_read, + s3c2410_watchdog_read, + s3c2410_watchdog_read +}; + +static CPUWriteMemoryFunc *s3c2410_watchdog_writefn[] = +{ + s3c2410_watchdog_write, + s3c2410_watchdog_write, + s3c2410_watchdog_write +}; + +static int +s3c2410_watchdog_init(x49gp_module_t *module) +{ + s3c2410_watchdog_t *watchdog; + int iotype; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + watchdog = malloc(sizeof(s3c2410_watchdog_t)); + if (NULL == watchdog) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + module->x49gp->progname, __FUNCTION__, __LINE__); + return -ENOMEM; + } + if (s3c2410_watchdog_data_init(watchdog)) { + free(watchdog); + return -ENOMEM; + } + + module->user_data = watchdog; + + watchdog->x49gp = module->x49gp; + module->x49gp->s3c2410_watchdog = watchdog; + + watchdog->timer = x49gp_new_timer(X49GP_TIMER_VIRTUAL, + s3c2410_watchdog_tick, watchdog); + +#ifdef QEMU_OLD + iotype = cpu_register_io_memory(0, s3c2410_watchdog_readfn, + s3c2410_watchdog_writefn, watchdog); +#else + iotype = cpu_register_io_memory(s3c2410_watchdog_readfn, + s3c2410_watchdog_writefn, watchdog); +#endif +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_WATCHDOG_BASE, S3C2410_MAP_SIZE, iotype); + return 0; +} + +static int +s3c2410_watchdog_exit(x49gp_module_t *module) +{ + s3c2410_watchdog_t *watchdog; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + watchdog = module->user_data; + if (watchdog->regs) + free(watchdog->regs); + free(watchdog); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_s3c2410_watchdog_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "s3c2410-watchdog", + s3c2410_watchdog_init, + s3c2410_watchdog_exit, + s3c2410_watchdog_reset, + s3c2410_watchdog_load, + s3c2410_watchdog_save, + NULL, &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/sim/.cvsignore b/sim/.cvsignore new file mode 100644 index 0000000..4671378 --- /dev/null +++ b/sim/.cvsignore @@ -0,0 +1 @@ +.depend diff --git a/sim/.svn/all-wcprops b/sim/.svn/all-wcprops new file mode 100644 index 0000000..e97d8f2 --- /dev/null +++ b/sim/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 28 +/p/x49gp/code/!svn/ver/1/sim +END +.cvsignore +K 25 +svn:wc:ra_dav:version-url +V 39 +/p/x49gp/code/!svn/ver/1/sim/.cvsignore +END diff --git a/sim/.svn/entries b/sim/.svn/entries new file mode 100644 index 0000000..87e27c3 --- /dev/null +++ b/sim/.svn/entries @@ -0,0 +1,65 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/sim +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +CVS +dir + +.cvsignore +file + + + + +2013-08-23T00:54:47.000000Z +488f0c41a36feb0e3c34a18494aefd3f +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +8 + diff --git a/sim/.svn/text-base/.cvsignore.svn-base b/sim/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..4671378 --- /dev/null +++ b/sim/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1 @@ +.depend diff --git a/sim/CVS/.svn/all-wcprops b/sim/CVS/.svn/all-wcprops new file mode 100644 index 0000000..a7665a8 --- /dev/null +++ b/sim/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 32 +/p/x49gp/code/!svn/ver/1/sim/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 43 +/p/x49gp/code/!svn/ver/1/sim/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 37 +/p/x49gp/code/!svn/ver/1/sim/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 40 +/p/x49gp/code/!svn/ver/1/sim/CVS/Entries +END diff --git a/sim/CVS/.svn/entries b/sim/CVS/.svn/entries new file mode 100644 index 0000000..4fa311f --- /dev/null +++ b/sim/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +11 +http://svn.code.sf.net/p/x49gp/code/sim/CVS +http://svn.code.sf.net/p/x49gp/code + + + +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + +481df3bd-3408-496c-b7de-451e46197bb5 + +Repository +file + + + + +2013-08-23T00:54:47.000000Z +9f8e001171432a129c6bf43877c5f5a5 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +10 + +Root +file + + + + +2013-08-23T00:54:47.000000Z +f51b768066a9e7d88829b19678326fcd +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +60 + +Entries +file + + + + +2013-08-23T00:54:47.000000Z +1efa19e73f625258cecf55ab9aa867b5 +2008-12-11T16:48:39.837984Z +1 +antiocles + + + + + + + + + + + + + + + + + + + + + +45 + diff --git a/sim/CVS/.svn/text-base/Entries.svn-base b/sim/CVS/.svn/text-base/Entries.svn-base new file mode 100644 index 0000000..abd9e8e --- /dev/null +++ b/sim/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,2 @@ +/.cvsignore/1.1/Thu Jun 8 05:41:42 2006// +D diff --git a/sim/CVS/.svn/text-base/Repository.svn-base b/sim/CVS/.svn/text-base/Repository.svn-base new file mode 100644 index 0000000..0374a59 --- /dev/null +++ b/sim/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +x49gp/sim diff --git a/sim/CVS/.svn/text-base/Root.svn-base b/sim/CVS/.svn/text-base/Root.svn-base new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/sim/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/sim/CVS/Entries b/sim/CVS/Entries new file mode 100644 index 0000000..abd9e8e --- /dev/null +++ b/sim/CVS/Entries @@ -0,0 +1,2 @@ +/.cvsignore/1.1/Thu Jun 8 05:41:42 2006// +D diff --git a/sim/CVS/Repository b/sim/CVS/Repository new file mode 100644 index 0000000..0374a59 --- /dev/null +++ b/sim/CVS/Repository @@ -0,0 +1 @@ +x49gp/sim diff --git a/sim/CVS/Root b/sim/CVS/Root new file mode 100644 index 0000000..6f29e94 --- /dev/null +++ b/sim/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@x49gp.cvs.sourceforge.net:/cvsroot/x49gp diff --git a/sram.c b/sram.c new file mode 100644 index 0000000..c34b56f --- /dev/null +++ b/sram.c @@ -0,0 +1,796 @@ +/* $Id: sram.c,v 1.18 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +typedef struct { + void *data; + void *shadow; + int fd; + size_t size; + uint32_t offset; + x49gp_t *x49gp; +} x49gp_sram_t; + +#define S3C2410_SRAM_BASE 0x08000000 +#define S3C2410_SRAM_SIZE 0x00080000 + +#define BASE 0xbcbb5 + +#define SATURN(r) ((target_phys_addr_t) &((saturn_cpu_t *)0)->r) + +static uint32_t +saturn_map_s2a(saturn_cpu_t *saturn, uint32_t saddr) +{ + uint32_t addr; + + addr = ldl_p(&saturn->read_map[saddr >> 12]) | ((saddr >> 1) & 0x7ff); + +// printf("SATURN: saddr %05x, addr %08x\n", saddr, addr); + + return addr; +} + +static uint32_t +saturn_peek(saturn_cpu_t *saturn, uint32_t saddr, uint32_t size) +{ + uint32_t addr, rot, mask, data; + uint64_t value; + + addr = saturn_map_s2a(saturn, saddr) & 0xfffffffc; + if (addr > 0x08080000) + return 0; + +// printf("SATURN: addr %08x\n", addr); + value = ((uint64_t) ldl_phys(addr)) | (((uint64_t) ldl_phys(addr + 4)) << 32); +// printf("SATURN: value %016llx\n", value); + + rot = (saddr & 7) << 2; + mask = (1ULL << (size << 2)) - 1; +// printf("SATURN: rot %u, mask %08x\n", rot, mask); + + data = ((uint32_t) (value >> rot)) & mask; +// printf("SATURN: data %08x\n", data); + + return data; +} + +static uint32_t +saturn_peek_address(saturn_cpu_t *saturn, uint32_t saddr) +{ + return saturn_peek(saturn, saddr, 5); +} + +static int +hxs2real(int hxs) +{ + int n = 0, c = 1; + + while (hxs) { + n += (hxs & 0xf) * c; + c *= 10; + hxs >>= 4; + } + return n; +} + +typedef struct { + uint32_t x; + uint32_t ml; + uint32_t mh; + uint8_t m; + uint8_t s; +} hp_real_t; + +static char * +real_number(saturn_cpu_t *saturn, uint32_t saddr, char *buffer, int ml, int xl) +{ + char *p = buffer; + char fmt[20]; + char m[16]; + hp_real_t r; + int re, xs; + int i; + uint32_t pc; + + pc = saddr; + + /* + * Read the number + */ + r.x = saturn_peek(saturn, pc, xl); + pc += xl; + r.ml = saturn_peek(saturn, pc, ml - 8); + pc += ml - 8; + r.mh = saturn_peek(saturn, pc, 8); + pc += 8; + r.m = saturn_peek(saturn, pc, 1); + pc += 1; + r.s = saturn_peek(saturn, pc, 1); + pc += 1; + + /* + * Figure out the exponent + */ + xs = 5; + while (--xl) + xs *= 10; + re = hxs2real(r.x); + if (re >= xs) + re = re - 2 * xs; + + if ((re >= 0) && (re < ml + 1)) { + if (r.s >= 5) + *p++ = '-'; + + sprintf(fmt, "%%.1X%%.8X%%.%dX", ml - 8); + sprintf(m, fmt, r.m, r.mh, r.ml); + + for (i = 0; i <= re; i++) + *p++ = m[i]; + *p++ = '.'; + for ( ; i < ml + 1; i++) + *p++ = m[i]; + p--; + while(*p == '0') + p--; + if (*p == '.') + p--; + *++p = '\0'; + + return buffer; + } + + if ((re < 0) && (re >= -ml - 1)) { + sprintf(fmt, "%%.1X%%.8X%%.%dX", ml - 8); + sprintf(m, fmt, r.m, r.mh, r.ml); + + for (i = ml; m[i] == '0'; i--) + ; + + if (-re <= ml - i + 1) { + if (r.s >= 5) + *p++ = '-'; + + *p++ = '.'; + + for (i = 1; i < -re; i++) + *p++ = '0'; + + for (i = 0; i < ml + 1; i++) + *p++ = m[i]; + p--; + while(*p == '0') + p--; + *++p = '\0'; + + return buffer; + } + } + + sprintf(fmt, "%%s%%X.%%.8X%%.%dX", ml - 8); + sprintf(p, fmt, (r.s >= 5) ? "-" : "", r.m, r.mh, r.ml); + + p += strlen(p) - 1; + + while(*p == '0') + p--; + *++p = '\0'; + + if (re) { + sprintf(p, "E%d", re); + p += strlen(p); + *p = '\0'; + } + + return buffer; +} + +static uint32_t +dump_object(x49gp_t *x49gp, x49gp_sram_t *sram, uint32_t saddr) +{ + saturn_cpu_t *saturn = (sram->data + 0x3340); + char buffer[128]; + uint32_t prolog, pc; + char c; + int i, n; + + pc = saddr; + + prolog = saturn_peek(saturn, pc, 5); + pc += 5; + + switch (prolog) { + case 0x02e48: + case 0x02e6d: + printf(" "); + n = saturn_peek(saturn, pc, 2); + pc += 2; + for (i = 0; i < n; i++) { + c = saturn_peek(saturn, pc, 2); + printf("%c", c); + pc += 2; + } + break; + + case 0x02a4e: + n = saturn_peek(saturn, pc, 5); + pc += 5; + if (n <= 16) { + printf(" #%08x%08xh", saturn_peek(saturn, pc + 8, 8), + saturn_peek(saturn, pc + 0, 8)); + } else { + printf(" C#"); + for (i = 0; i < n; i++) { + printf("%x", saturn_peek(saturn, pc + i, 1)); + } + } + pc += n; + break; + + case 0x02911: + printf(" <%05x>", saturn_peek(saturn, pc, 5)); + pc += 5; + break; + + case 0x02933: + printf(" %%%s", real_number(saturn, pc, buffer, 11, 3)); + pc += 16; + break; + + case 0x02955: + printf(" %%%%%s", real_number(saturn, pc, buffer, 14, 5)); + pc += 21; + break; + + case 0x02e92: + printf(" <%03x %03x>", saturn_peek(saturn, pc + 0, 3), + saturn_peek(saturn, pc + 3, 3)); + pc += 6; + break; + + case 0x026ac: + printf(" <%03x %04x>", saturn_peek(saturn, pc + 0, 3), + saturn_peek(saturn, pc + 3, 4)); + pc += 7; + break; + + case 0x02ab8: + printf(" '"); + while (1) { + prolog = saturn_peek(saturn, pc, 5); + if (prolog == 0x0312b) { + pc += 5; + break; + } + pc += dump_object(x49gp, sram, pc); + } + printf(" '"); + break; + + case 0x02d9d: + printf(" :"); + while (1) { + prolog = saturn_peek(saturn, pc, 5); + if (prolog == 0x0312b) { + pc += 5; + break; + } + pc += dump_object(x49gp, sram, pc); + } + printf(" ;"); + break; + + default: + printf(" %05x", prolog); + break; + } + + return pc - saddr; +} + +static void +debug_saturn(x49gp_t *x49gp, x49gp_sram_t *sram) +{ + saturn_cpu_t *saturn = (sram->data + 0x3340); + uint32_t sp, se; + uint32_t prolog; + uint32_t rsp; + uint32_t first; + static uint32_t prev_first = 0; + static int state = 0; + int depth; + int i; + +// printf("SATURN: %p, RPLTOP: %08x\n", saturn, saturn_map_s2a(saturn, SAT_RPLTOP)); +// printf("SATURN: %p, RSKTOP: %08x\n", saturn, saturn_map_s2a(saturn, SAT_RSKTOP)); + +// rpltop = saturn_peek_address(saturn, SAT_RPLTOP); +// printf("SATURN: RPLTOP: %05x\n", rpltop); + + rsp = saturn_peek_address(saturn, SAT_RSKTOP); + if (rsp == 0) + return; + + first = saturn_peek_address(saturn, rsp - 5); + if (first == prev_first) { + return; + } + prev_first = first; + + if (first == (BASE + 0x14a54)) { + state = 1; + } + if (state == 0) + return; + + printf("SATURN: %p, rsp: %05x %08x\n", saturn, rsp, saturn_map_s2a(saturn, rsp)); + + for (i = 0; ; i++) { + rsp -= 5; + + se = saturn_peek_address(saturn, rsp); + if (se == 0) + break; + + if (se > BASE) + printf("SATURN: RSTK %02u: %05x <%05x>\n", i, se, se - BASE); + else + printf("SATURN: RSTK %02u: %05x\n", i, se); + } + + + depth = (saturn_peek_address(saturn, SAT_EDITLINE) - saturn_peek_address(saturn, SAT_DSKTOP) - 5) / 5; + + printf("SATURN: depth %d\n", depth); + + sp = saturn_peek_address(saturn, SAT_EDITLINE) - 10; + + for (i = 0; i < depth; i++) { + se = saturn_peek_address(saturn, sp); + sp -= 5; + + prolog = saturn_peek(saturn, se, 5); + + printf("SATURN: %02u: <%05x> <%05x>", depth - i, se, prolog); + + dump_object(x49gp, sram, se); + + printf("\n"); + } +} + +static uint32_t +sram_get_word(void *opaque, target_phys_addr_t offset) +{ + x49gp_sram_t *sram = opaque; + uint32_t data; + +#ifdef QEMU_OLD + offset -= S3C2410_SRAM_BASE; +#endif + data = ldl_p(sram->data + offset); + +#if 0 + if (offset == 0x00000a1c) { + printf("read SRAM at offset %08x: %08x (pc %08x)\n", offset, data, x49gp->arm->Reg[15]); + } +#endif + +#ifdef DEBUG_X49GP_SYSRAM_READ + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("read SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_READ + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("read SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_READ + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("read SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif + + return data; +} + +static uint32_t +sram_get_halfword(void *opaque, target_phys_addr_t offset) +{ + x49gp_sram_t *sram = opaque; + unsigned short data; + +#ifdef QEMU_OLD + offset -= S3C2410_SRAM_BASE; +#endif + data = lduw_p(sram->data + offset); + +#ifdef DEBUG_X49GP_SYSRAM_READ + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("read SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_READ + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("read SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_READ + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("read SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif + + return data; +} + +static uint32_t +sram_get_byte(void *opaque, target_phys_addr_t offset) +{ + x49gp_sram_t *sram = opaque; + unsigned char data; + +#ifdef QEMU_OLD + offset -= S3C2410_SRAM_BASE; +#endif + data = ldub_p(sram->data + offset); + +#ifdef DEBUG_X49GP_SYSRAM_READ + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("read SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_READ + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("read SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_READ + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("read SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif + + return data; +} + +static void +sram_put_word(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_sram_t *sram = opaque; + +#ifdef QEMU_OLD + // offset -= S3C2410_SRAM_BASE; + offset -= (target_phys_addr_t)phys_ram_base + sram->offset; +#endif + + if (offset == 0x00000a1c) { + printf("write SRAM 4 at offset %08x: %08x (pc %08x)\n", + offset, data, sram->x49gp->env->regs[15]); + } + + debug_saturn(sram->x49gp, sram); + +#if 0 + if (offset == 0x3340 + SATURN(D1)) { + printf("write D1 at offset %08x: %08x (pc %08x)\n", + offset, data, sram->x49gp->env->regs[15]); + } + if (offset == 0x3340 + SATURN(A)) { + printf("write A at offset %08x: %08x (pc %08x)\n", + offset, data, sram->x49gp->env->regs[15]); + } + if (offset == 0x3340 + SATURN(A) + 8) { + printf("write Al at offset %08x: %08x (pc %08x)\n", + offset, data, sram->x49gp->env->regs[15]); + } +#endif + +#ifdef DEBUG_X49GP_SYSRAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("write SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("write SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_WRITE + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("write SRAM 4 at offset %08x: %08x\n", offset, data); + } +#endif + + stl_p(sram->data + offset, data); +} + +static void +sram_put_halfword(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_sram_t *sram = opaque; + +#ifdef QEMU_OLD + // offset -= S3C2410_SRAM_BASE; + offset -= (target_phys_addr_t)phys_ram_base + sram->offset; +#endif + data &= 0xffff; + +#ifdef DEBUG_X49GP_SYSRAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("write SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("write SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_WRITE + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("write SRAM 2 at offset %08x: %04x\n", offset, data); + } +#endif + + stw_p(sram->data + offset, data); +} + +static void +sram_put_byte(void *opaque, target_phys_addr_t offset, uint32_t data) +{ + x49gp_sram_t *sram = opaque; + +#ifdef QEMU_OLD + // offset -= S3C2410_SRAM_BASE; + offset -= (target_phys_addr_t)phys_ram_base + sram->offset; +#endif + data &= 0xff; + +#ifdef DEBUG_X49GP_SYSRAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00000000) { + printf("write SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_ERAM_WRITE + if ((offset & ~(0x0001ffff)) == 0x00020000) { + printf("write SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif +#ifdef DEBUG_X49GP_IRAM_WRITE + if ((offset & ~(0x0003ffff)) == 0x00040000) { + printf("write SRAM 1 at offset %08x: %02x\n", offset, data); + } +#endif + + stb_p(sram->data + offset, data); +} + +static CPUReadMemoryFunc *sram_readfn[] = +{ + sram_get_byte, + sram_get_halfword, + sram_get_word +}; + +static CPUWriteMemoryFunc *sram_writefn[] = +{ + sram_put_byte, + sram_put_halfword, + sram_put_word +}; + +static int +sram_load(x49gp_module_t *module, GKeyFile *key) +{ + x49gp_sram_t *sram = module->user_data; + char *filename; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + filename = x49gp_module_get_filename(module, key, "filename"); + if (NULL == filename) { + fprintf(stderr, "%s: %s:%u: key \"filename\" not found\n", + module->name, __FUNCTION__, __LINE__); + return -ENOENT; + } + + sram->fd = open(filename, O_RDWR); + if (sram->fd < 0) { + error = -errno; + fprintf(stderr, "%s: %s:%u: open %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + return error; + } + + sram->size = 0x00080000; + + sram->data = mmap(phys_ram_base + sram->offset, sram->size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + sram->fd, 0); + if (sram->data == (void *) -1) { + error = -errno; + fprintf(stderr, "%s: %s:%u: mmap %s: %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + close(sram->fd); + sram->fd = -1; + return error; + } + + sram->shadow = mmap(phys_ram_base + sram->offset + sram->size, + sram->size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + sram->fd, 0); + if (sram->shadow == (void *) -1) { + error = -errno; + fprintf(stderr, "%s: %s:%u: mmap %s (shadow): %s\n", + module->name, __FUNCTION__, __LINE__, + filename, strerror(errno)); + g_free(filename); + close(sram->fd); + sram->fd = -1; + return error; + } + + sram->x49gp->sram = phys_ram_base + sram->offset; + + g_free(filename); + return 0; +} + +static int +sram_save(x49gp_module_t *module, GKeyFile *key) +{ + x49gp_sram_t *sram = module->user_data; + int error; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + error = msync(sram->data, sram->size, MS_ASYNC); + if (error) { + fprintf(stderr, "%s:%u: msync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + error = fsync(sram->fd); + if (error) { + fprintf(stderr, "%s:%u: fsync: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + return error; + } + + return 0; +} + +static int +sram_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + return 0; +} + +static int +sram_init(x49gp_module_t *module) +{ + x49gp_sram_t *sram; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + sram = malloc(sizeof(x49gp_sram_t)); + if (NULL == sram) { + fprintf(stderr, "%s:%u: Out of memory\n", + __FUNCTION__, __LINE__); + return -ENOMEM; + } + memset(sram, 0, sizeof(x49gp_sram_t)); + + sram->fd = -1; + + module->user_data = sram; + sram->x49gp = module->x49gp; + + sram->data = (void *) -1; + sram->shadow = (void *) -1; + sram->offset = phys_ram_size; + phys_ram_size += S3C2410_SRAM_SIZE; + phys_ram_size += S3C2410_SRAM_SIZE; + +#if 0 +{ + int iotype; + + iotype = cpu_register_io_memory(0, sram_readfn, sram_writefn, sram); +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_SRAM_BASE, + S3C2410_SRAM_SIZE, + sram->offset | iotype | IO_MEM_ROMD); + + iotype = cpu_register_io_memory(0, sram_readfn, sram_writefn, sram); +printf("%s: iotype %08x\n", __FUNCTION__, iotype); + cpu_register_physical_memory(S3C2410_SRAM_BASE + S3C2410_SRAM_SIZE, + S3C2410_SRAM_SIZE, + (sram->offset + S3C2410_SRAM_SIZE) | iotype | IO_MEM_ROMD); +} +#else + cpu_register_physical_memory(S3C2410_SRAM_BASE, S3C2410_SRAM_SIZE, + sram->offset | IO_MEM_RAM); + cpu_register_physical_memory(S3C2410_SRAM_BASE + S3C2410_SRAM_SIZE, + S3C2410_SRAM_SIZE, + (sram->offset + S3C2410_SRAM_SIZE) | IO_MEM_RAM); +#endif + + return 0; +} + +static int +sram_exit(x49gp_module_t *module) +{ + x49gp_sram_t *sram; + +#ifdef DEBUG_X49GP_MODULES + printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__); +#endif + + if (module->user_data) { + sram = module->user_data; + + if (sram->shadow != (void *) -1) { + munmap(sram->shadow, sram->size); + } + if (sram->data != (void *) -1) { + munmap(sram->data, sram->size); + } + if (sram->fd >= 0) { + close(sram->fd); + } + + free(sram); + } + + x49gp_module_unregister(module); + free(module); + + return 0; +} + +int +x49gp_sram_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "sram", sram_init, sram_exit, + sram_reset, sram_load, sram_save, NULL, + &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/symbol.c b/symbol.c new file mode 100644 index 0000000..10d6aa8 --- /dev/null +++ b/symbol.c @@ -0,0 +1,279 @@ +/* $Id: symbol.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include + +#include +#include + +#include + +static const cairo_path_data_t symbol_square_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.100 ), + SYMBOL_LINE_TO( 0.500, 0.000 ), + SYMBOL_LINE_TO( 0.000, 0.500 ), + SYMBOL_LINE_TO( -0.500, 0.000 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(square, 0.7, 0.0, 0.1, 0.1, 0.6, 0.6); + + +static const cairo_path_data_t symbol_triangleup_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.000 ), + SYMBOL_LINE_TO( 0.800, 0.000 ), + SYMBOL_LINE_TO( -0.400, 0.693 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(triangleup, 1.0, 0.0, 0.1, 0.0, 0.9, 0.693); + + +static const cairo_path_data_t symbol_triangleright_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.000 ), + SYMBOL_LINE_TO( 0.000, 0.800 ), + SYMBOL_LINE_TO( 0.693, -0.400 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(triangleright, 0.893, 0.0, 0.1, 0.0, 0.793, 0.8); + + +static const cairo_path_data_t symbol_arrowleftdblfull_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.370 ), + SYMBOL_LINE_TO( 0.652, 0.500 ), + SYMBOL_LINE_TO( 0.000, -0.250 ), + SYMBOL_LINE_TO( 1.000, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.500 ), + SYMBOL_LINE_TO( -1.000, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.250 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(arrowleftdblfull, 1.852, 0.0, 0.1, -0.13, 1.752, 0.87); + +static const cairo_path_data_t symbol_uparrowleft_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.500 ), + SYMBOL_LINE_TO( 0.600, 0.200 ), + SYMBOL_LINE_TO( 0.000, -0.150 ), + SYMBOL_LINE_TO( 0.500, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.550 ), + SYMBOL_LINE_TO( -0.100, 0.000 ), + SYMBOL_LINE_TO( 0.000, 0.450 ), + SYMBOL_LINE_TO( -0.400, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.150 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(uparrowleft, 1.3, 0.0, 0.1, 0.0, 1.2, 0.7); + + +static const cairo_path_data_t symbol_uparrowright_path_data[] = +{ + SYMBOL_MOVE_TO( 1.200, 0.500 ), + SYMBOL_LINE_TO( -0.600, 0.200 ), + SYMBOL_LINE_TO( 0.000, -0.150 ), + SYMBOL_LINE_TO( -0.500, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.550 ), + SYMBOL_LINE_TO( 0.100, 0.000 ), + SYMBOL_LINE_TO( 0.000, 0.450 ), + SYMBOL_LINE_TO( 0.400, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.150 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(uparrowright, 1.3, 0.0, 0.1, 0.0, 1.2, 0.7); + + +static const cairo_path_data_t symbol_tick_path_data[] = +{ + SYMBOL_MOVE_TO( 0.100, 0.400 ), + SYMBOL_LINE_TO( 0.000, 0.450 ), + SYMBOL_LINE_TO( 0.150, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.450 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(tick, 0.35, 0.0, 0.1, 0.4, 0.25, 0.85); + + +static const cairo_path_data_t symbol_radical_path_data[] = +{ + SYMBOL_MOVE_TO( 0.000, 0.500 ), + SYMBOL_LINE_TO( 0.214, 0.100 ), + SYMBOL_LINE_TO( 0.213, -0.456 ), + SYMBOL_LINE_TO( 0.229, 0.856 ), + SYMBOL_LINE_TO( 0.077, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.100 ), + SYMBOL_LINE_TO( -0.281, -1.050 ), + SYMBOL_LINE_TO( -0.287, 0.616 ), + SYMBOL_LINE_TO( -0.123, -0.057 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(radical, 0.733, 0.0, 0.0, -0.15, 0.733, 1.0); + + +static const cairo_path_data_t symbol_overscore_path_data[] = +{ + SYMBOL_MOVE_TO( 0.000, 1.000 ), + SYMBOL_LINE_TO( 0.900, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.100 ), + SYMBOL_LINE_TO( -0.900, 0.000 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(overscore, 0.8, 0.0, 0.0, 0.9, 0.9, 1.0); + + +static const cairo_path_data_t symbol_minus_path_data[] = +{ + SYMBOL_MOVE_TO( 0.050, 0.312 ), + SYMBOL_LINE_TO( 0.000, 0.118 ), + SYMBOL_LINE_TO( 0.500, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.118 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(minus, 0.6, 0.0, 0.05, 0.312, 0.55, 0.430); + + +static const cairo_path_data_t symbol_divide_path_data[] = +{ + SYMBOL_MOVE_TO( 0.050, 0.312 ), + SYMBOL_LINE_TO( 0.000, 0.118 ), + SYMBOL_LINE_TO( 0.500, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.118 ), + SYMBOL_CLOSE_PATH(), + SYMBOL_MOVE_TO( 0.180, -0.108 ), + SYMBOL_LINE_TO( 0.135, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.135 ), + SYMBOL_LINE_TO( -0.135, 0.000 ), + SYMBOL_CLOSE_PATH(), + SYMBOL_MOVE_TO( 0.000, 0.334 ), + SYMBOL_LINE_TO( 0.000, 0.135 ), + SYMBOL_LINE_TO( 0.135, 0.000 ), + SYMBOL_LINE_TO( 0.000, -0.135 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(divide, 0.6, 0.0, 0.05, 0.069, 0.55, 0.673); + + +static const cairo_path_data_t symbol_divisionslash_path_data[] = +{ + SYMBOL_MOVE_TO( 0.050, 0.000 ), + SYMBOL_LINE_TO( 0.345, 0.739 ), + SYMBOL_LINE_TO( 0.130, 0.000 ), + SYMBOL_LINE_TO( -0.345, -0.739 ), + SYMBOL_CLOSE_PATH() +}; + +SYMBOL(divisionslash, 0.575, 0.000, 0.050, 0.000, 0.525, 0.739); + + +CONTROL(beginsuperscript, 0.0, 0.5, 1.0, 0.8); +CONTROL(endsuperscript, 0.0, 0.5, 1.25, 1.0); + +CONTROL(kern_m1, -0.1, 0.0, 1.0, 1.0); +CONTROL(kern_m2, -0.2, 0.0, 1.0, 1.0); +CONTROL(kern_m3, -0.3, 0.0, 1.0, 1.0); +CONTROL(kern_m4, -0.4, 0.0, 1.0, 1.0); +CONTROL(kern_m5, -0.5, 0.0, 1.0, 1.0); +CONTROL(kern_m6, -0.6, 0.0, 1.0, 1.0); +CONTROL(kern_m7, -0.7, 0.0, 1.0, 1.0); +CONTROL(kern_m8, -0.8, 0.0, 1.0, 1.0); +CONTROL(kern_m9, -0.9, 0.0, 1.0, 1.0); + + +typedef struct { + const char *name; + const x49gp_symbol_t *symbol; +} symbol_name_t; + +static const symbol_name_t symbol_names[] = +{ + { ".notdef", &symbol_square }, + { "arrowleftdblfull", &symbol_arrowleftdblfull }, + { "divide", &symbol_divide }, + { "divisionslash", &symbol_divisionslash }, + { "minus", &symbol_minus }, + { "overscore", &symbol_overscore }, + { "radical", &symbol_radical }, + { "square", &symbol_square }, + { "tick", &symbol_tick }, + { "triangleright", &symbol_triangleright }, + { "triangleup", &symbol_triangleup }, + { "uparrowleft", &symbol_uparrowleft }, + { "uparrowright", &symbol_uparrowright }, + { "super", &symbol_beginsuperscript }, + { "/super", &symbol_endsuperscript }, + { "kern-1", &symbol_kern_m1 }, + { "kern-2", &symbol_kern_m2 }, + { "kern-3", &symbol_kern_m3 }, + { "kern-4", &symbol_kern_m4 }, + { "kern-5", &symbol_kern_m5 }, + { "kern-6", &symbol_kern_m6 }, + { "kern-7", &symbol_kern_m7 }, + { "kern-8", &symbol_kern_m8 }, + { "kern-9", &symbol_kern_m9 }, + { NULL, NULL } +}; +#define NR_SYMBOLS (sizeof(symbol_names) / sizeof(symbol_names[0]) - 1) + +int +symbol_lookup_glyph_by_name(const char *name, int namelen, gunichar *glyph) +{ + const symbol_name_t *symname; + int i = 0; + + /* + * Code symbols as Unicode Private Use from U+E000 on... + */ + + symname = symbol_names; + while (symname->name) { + if ((strlen(symname->name) == namelen) && + !strncmp(symname->name, name, namelen)) { + if (glyph) { + *glyph = 0xe000 + i; + } + return 1; + } + + symname++; + i++; + } + + return 0; +} + +const x49gp_symbol_t * +symbol_get_by_glyph(gunichar glyph) +{ + int index = glyph - 0xe000; + + if ((index >= 0) && (index < NR_SYMBOLS)) { + return symbol_names[index].symbol; + } + + return NULL; +} + +const x49gp_symbol_t * +symbol_get_by_name(const char *name) +{ + gunichar glyph; + + if (symbol_lookup_glyph_by_name(name, strlen(name), &glyph)) { + return symbol_get_by_glyph(glyph); + } + + return NULL; +} diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..9a5258f --- /dev/null +++ b/timer.c @@ -0,0 +1,329 @@ +/* $Id: timer.c,v 1.4 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +typedef struct { + long type; +} x49gp_clock_t; + +struct x49gp_timer_s { + long type; + int64_t expires; + x49gp_timer_cb_t cb; + void *user_data; + x49gp_timer_t *next; +}; + +#ifdef QEMU_OLD // LD TEMPO HACK +typedef x49gp_timer_t QEMUTimer; +#endif +typedef x49gp_timer_cb_t QEMUTimerCB; +typedef void * QEMUClock; +QEMUClock *rt_clock = (void *) X49GP_TIMER_REALTIME; +QEMUClock *vm_clock = (void *) X49GP_TIMER_VIRTUAL; +int64_t ticks_per_sec = 1000000; + +static x49gp_timer_t *x49gp_timer_lists[2]; + +int64_t +x49gp_get_clock(void) +{ + struct timeval tv; + int64_t us; + + gettimeofday(&tv, NULL); + + us = tv.tv_sec * 1000000LL + tv.tv_usec; + + return us; +} + +x49gp_timer_t * +x49gp_new_timer(long type, x49gp_timer_cb_t cb, void *user_data) +{ + x49gp_timer_t *ts; + + ts = malloc(sizeof(x49gp_timer_t)); + if (NULL == ts) { + return NULL; + } + memset(ts, 0, sizeof(x49gp_timer_t)); + + ts->type = type; + ts->cb = cb; + ts->user_data = user_data; + + return ts; +} + +void +x49gp_free_timer(x49gp_timer_t *ts) +{ + free(ts); +} + +void +x49gp_del_timer(x49gp_timer_t *ts) +{ + x49gp_timer_t **pt, *t; + +// printf("%s: ts %p\n", __FUNCTION__, ts); + pt = &x49gp_timer_lists[ts->type]; + while (1) { + t = *pt; + if (NULL == t) + break; + if (t == ts) { + *pt = t->next; + ts->next = NULL; + break; + } + pt = &t->next; + } +} + +void +x49gp_mod_timer(x49gp_timer_t *ts, int64_t expires) +{ + x49gp_timer_t **pt, *t; + + x49gp_del_timer(ts); + +// printf("%s: ts %p, expires %lld\n", __FUNCTION__, ts, expires); + pt = &x49gp_timer_lists[ts->type]; + while (1) { + t = *pt; + if (NULL == t) + break; + if (t->expires > expires) + break; + pt = &t->next; + } + + ts->expires = expires; + ts->next = *pt; + *pt = ts; +} + +int +x49gp_timer_pending(x49gp_timer_t *ts) +{ + x49gp_timer_t *t; + + for (t = x49gp_timer_lists[ts->type]; t; t = t->next) { + if (t == ts) + return 1; + } + + return 0; +} + +int64_t +x49gp_timer_expires(x49gp_timer_t *ts) +{ + return ts->expires; +} + +static int +x49gp_timer_expired(x49gp_timer_t *timer_head, int64_t current_time) +{ + if (NULL == timer_head) + return 0; + return (timer_head->expires <= current_time); +} + +QEMUTimer * +qemu_new_timer(QEMUClock *clock, QEMUTimerCB cb, void *opaque) +{ + return x49gp_new_timer((long) clock, cb, opaque); +} + +void +qemu_free_timer(QEMUTimer *ts) +{ + return x49gp_free_timer(ts); +} + +void +qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) +{ + return x49gp_mod_timer(ts, expire_time); +} + +void +qemu_del_timer(QEMUTimer *ts) +{ + return x49gp_del_timer(ts); +} + +int +qemu_timer_pending(QEMUTimer *ts) +{ + return x49gp_timer_pending(ts); +} + +int64_t +qemu_get_clock(QEMUClock *clock) +{ + return x49gp_get_clock(); +} + +static void +x49gp_run_timers(x49gp_timer_t **ptimer_head, int64_t current_time) +{ + x49gp_timer_t *ts; + +// printf("%s: now %lld\n", __FUNCTION__, current_time); + while (1) { + ts = *ptimer_head; + if (NULL == ts || ts->expires > current_time) + break; + + *ptimer_head = ts->next; + ts->next = NULL; + +// printf("%s: call ts %p\n", __FUNCTION__, ts); + ts->cb(ts->user_data); +// printf("%s: ts %p done\n", __FUNCTION__, ts); + } + +// printf("%s: timers done\n", __FUNCTION__); +} + +static void +x49gp_alarm_handler(int sig) +{ + if (x49gp_timer_expired(x49gp_timer_lists[X49GP_TIMER_VIRTUAL], + x49gp_get_clock()) || + x49gp_timer_expired(x49gp_timer_lists[X49GP_TIMER_REALTIME], + x49gp_get_clock())) { +#ifdef QEMU_OLD + if (cpu_single_env && ! (cpu_single_env->interrupt_request & CPU_INTERRUPT_EXIT)) { + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + } +#else + if (cpu_single_env && ! cpu_single_env->exit_request) { + cpu_exit(cpu_single_env); + } +#endif + } +} + +static void +x49gp_main_loop_wait(x49gp_t *x49gp, int timeout) +{ +// printf("%s: timeout: %d\n", __FUNCTION__, timeout); + +#if 0 + if (gdb_poll(x49gp->env)) { + gdb_handlesig(x49gp->env, 0); + } else +#endif + poll(NULL, 0, timeout); + + if (x49gp->arm_idle != X49GP_ARM_OFF) { + x49gp_run_timers(&x49gp_timer_lists[X49GP_TIMER_VIRTUAL], + x49gp_get_clock()); + } + + x49gp_run_timers(&x49gp_timer_lists[X49GP_TIMER_REALTIME], + x49gp_get_clock()); + +// printf("%s: done\n", __FUNCTION__); +} + +int +x49gp_main_loop(x49gp_t *x49gp) +{ + int prev_idle; + int ret, timeout; + + while (! x49gp->arm_exit) { + prev_idle = x49gp->arm_idle; + + if (x49gp->arm_idle == X49GP_ARM_RUN) { +#ifdef DEBUG_X49GP_TIMER_IDLE +printf("%lld: %s: call cpu_exec(%p)\n", x49gp_get_clock(), __FUNCTION__, x49gp->env); +#endif + ret = cpu_exec(x49gp->env); +#ifdef DEBUG_X49GP_TIMER_IDLE +printf("%lld: %s: cpu_exec(): %d, PC %08x\n", x49gp_get_clock(), __FUNCTION__, ret, x49gp->env->regs[15]); +#endif + +if (x49gp->env->regs[15] == 0x8620) { +printf("PC %08x: SRAM %08x: %08x %08x %08x <%08x>\n", x49gp->env->regs[15], 0x08000a0c, + * ((uint32_t *) &x49gp->sram[0x0a00]), + * ((uint32_t *) &x49gp->sram[0x0a04]), + * ((uint32_t *) &x49gp->sram[0x0a08]), + * ((uint32_t *) &x49gp->sram[0x0a0c])); +* ((uint32_t *) &x49gp->sram[0x0a0c]) = 0x00000000; +} + +#if 0 + if (ret == EXCP_DEBUG) { + gdb_handlesig(x49gp->env, SIGTRAP); + } +#endif + + if (x49gp->arm_idle != prev_idle) { + if (x49gp->arm_idle == X49GP_ARM_OFF) { + x49gp_lcd_update(x49gp); + cpu_reset(x49gp->env); + } + } + + if (ret == EXCP_HALTED) { + timeout = 10; + } else { + timeout = 0; + } + } else { + timeout = 1; + } + + x49gp_main_loop_wait(x49gp, timeout); + } + + return 0; +} + +int +x49gp_timer_init(x49gp_t *x49gp) +{ + struct sigaction sa; + struct itimerval it; + + x49gp_timer_lists[X49GP_TIMER_VIRTUAL] = NULL; + x49gp_timer_lists[X49GP_TIMER_REALTIME] = NULL; + + sigfillset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = x49gp_alarm_handler; + sigaction(SIGALRM, &sa, NULL); + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1000; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1000; + + setitimer(ITIMER_REAL, &it, NULL); + return 0; +} diff --git a/tiny_font.c b/tiny_font.c new file mode 100644 index 0000000..5692bb0 --- /dev/null +++ b/tiny_font.c @@ -0,0 +1,205 @@ +/* $Id: tiny_font.c,v 1.6 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const bitmap_font_t tiny_font = +{ + 7, + -3, + { + GLYPH(tiny, notdef), + + SPACE("space", 4, 0), + GLYPH(tiny, quotedbl), + GLYPH(tiny, numbersign), + GLYPH(tiny, ampersand), + GLYPH(tiny, parenleft), + GLYPH(tiny, parenright), + GLYPH(tiny, comma), + GLYPH(tiny, hyphen), + GLYPH(tiny, period), + GLYPH(tiny, slash), + + GLYPH(tiny, zero), + GLYPH(tiny, one), + GLYPH(tiny, two), + GLYPH(tiny, three), + + GLYPH(tiny, colon), + + GLYPH(tiny, less), + GLYPH(tiny, equal), + GLYPH(tiny, greater), + + GLYPH(tiny, A), + GLYPH(tiny, B), + GLYPH(tiny, C), + GLYPH(tiny, D), + GLYPH(tiny, E), + GLYPH(tiny, F), + GLYPH(tiny, G), + GLYPH(tiny, H), + GLYPH(tiny, I), + GLYPH(tiny, J), + GLYPH(tiny, K), + GLYPH(tiny, L), + GLYPH(tiny, M), + GLYPH(tiny, N), + GLYPH(tiny, O), + GLYPH(tiny, P), + GLYPH(tiny, Q), + GLYPH(tiny, R), + GLYPH(tiny, S), + GLYPH(tiny, T), + GLYPH(tiny, U), + GLYPH(tiny, V), + GLYPH(tiny, W), + GLYPH(tiny, X), + GLYPH(tiny, Y), + GLYPH(tiny, Z), + + GLYPH(tiny, bracketleft), + GLYPH(tiny, bracketright), + GLYPH(tiny, underscore), + + GLYPH(tiny, i), + + GLYPH(tiny, overscore), + GLYPH(tiny, arrowleft), + GLYPH(tiny, arrowright), + GLYPH(tiny, guillemotleft), + GLYPH(tiny, guillemotright), + + GLYPH(tiny, braceleft), + GLYPH(tiny, braceright), + + GLYPH(tiny, large_comma), + + GLYPH(tiny, xsuperior), + GLYPH(tiny, twosuperior), + + GLYPH(tiny, math_e), + GLYPH(tiny, math_x), + GLYPH(tiny, math_y), + GLYPH(tiny, math_pi), + GLYPH(tiny, math_summation), + GLYPH(tiny, math_radical), + GLYPH(tiny, math_partialdiff), + GLYPH(tiny, math_integral), + GLYPH(tiny, math_infinity), + + GLYPH(tiny, math_numbersign), + GLYPH(tiny, math_less), + GLYPH(tiny, math_greater), + GLYPH(tiny, math_lessequal), + GLYPH(tiny, math_greaterequal), + GLYPH(tiny, math_equal), + GLYPH(tiny, math_notequal), + + GLYPH(tiny, math_arrowleft), + GLYPH(tiny, math_arrowright), + GLYPH(tiny, math_downarrowleft), + GLYPH(tiny, math_downarrowright), + + SPACE("kern-1", -1, -1), + SPACE("kern-2", -2, -2), + SPACE("kern-3", -3, -3), + SPACE("kern-4", -4, -4), + SPACE("kern-5", -5, -5), + SPACE("kern-6", -6, -6), + SPACE("kern-7", -7, -7), + + { NULL } + } +}; diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..16f51f2 --- /dev/null +++ b/ui.c @@ -0,0 +1,2411 @@ +/* $Id: ui.c,v 1.34 2008/12/11 12:18:17 ecd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(__linux__) +#define X49GP_UI_NORMAL_FONT "urw gothic l" +#else +#define X49GP_UI_NORMAL_FONT "Century Gothic" +#endif + + +static const x49gp_ui_key_t x49gp_ui_keys[] = +{ + { + "F1", "A", "Y=", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1 + }, + { + "F2", "B", "WIN", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2 + }, + { + "F3", "C", "GRAPH", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3 + }, + { + "F4", "D", "2D/3D", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4 + }, + { + "F5", "E", "TBLSET", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5 + }, + { + "F6", "F", "TABLE", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6 + }, + { + "APPS", "G", "FILES", "BEGIN", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7 + }, + { + "MODE", "H", "CUSTOM", "END", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5 + }, + { + "TOOL", "I", "i", "I", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6 + }, + { + "V\\kern-1 AR", "J", "UPDIR", "COPY", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7 + }, + { + "STO \\triangleright", "K", "RCL", "CUT", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1 + }, + { + "NXT", "L", "PREV", "PASTE", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4 + }, + { + "HIST", "M", "CMD", "UNDO", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1 + }, + { + "EV\\kern-1 AL", "N", "PRG", "CHARS", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1 + }, + { + "\\tick", "O", "MTRW", "EQW", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1 + }, + { + "S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1 + }, + { + "\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 0.0, 0, + 238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1 + }, + { + "Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2 + }, + { + "\\radical\\overscore\\kern-7 X", "R", + "\\math_x\\twosuperior", + "\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2 + }, + { + "SIN", "S", "ASIN", "\\math_summation", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2 + }, + { + "COS", "T", "ACOS", "\\math_partialdiff", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2 + }, + { + "TAN", "U", "ATAN", "\\math_integral", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2 + }, + { + "EEX", "V", "10\\xsuperior", "LOG", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3 + }, + { + "+\\divisionslash\\minus", "W", + "\\math_notequal", + "\\math_equal", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3 + }, + { + "X", "X", + "\\math_lessequal", + "\\math_less", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3 + }, + { + "1/X", "Y", + "\\math_greaterequal", + "\\math_greater", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3 + }, + { + "\\divide", "Z", "ABS", "ARG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE, + 238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3 + }, + { + "ALPHA", NULL, "USER", "ENTRY", NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 267, 46, 32, 0, 0, 0, 0, 4 + }, + { + "7", NULL, "S.SLV", "NUM.SLV", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4 + }, + { + "8", NULL, "EXP&LN", "TRIG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4 + }, + { + "9", NULL, "FINANCE", "TIME", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4 + }, + { + "\\multiply", NULL, "[ ]", "\" \"", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4 + }, + { + "\\uparrowleft", NULL, NULL, NULL, NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 313, 46, 32, 0, 0, 0, 0, 5 + }, + { + "4", NULL, "CALC", "ALG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5 + }, + { + "5", NULL, "MATRICES", "STAT", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5 + }, + { + "6", NULL, "CONVERT", "UNITS", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5 + }, + { + "\\minus", NULL, "( )", "_", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5 + }, + { + "\\uparrowright", NULL, NULL, NULL, NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 359, 46, 32, 0, 0, 0, 0, 6 + }, + { + "1", NULL, "ARITH", "CMPLX", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6 + }, + { + "2", NULL, "DEF", "LIB", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6 + }, + { + "3", NULL, "\\math_numbersign", "BASE", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6 + }, + { + "+", NULL, + "{ }", + "\\guillemotleft\\ \\guillemotright", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6 + }, + { + "ON", NULL, "CONT", "OFF", "CANCEL", + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 405, 46, 32, 0, 0, 0, 0, 0 + }, + { + "0", NULL, + "\\math_infinity", + "\\math_arrowright", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7 + }, + { + "\\bullet", NULL, + ": :", + "\\math_downarrowleft", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7 + }, + { + "SPC", NULL, + "\\math_pi", + "\\large_comma", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7 + }, + { + "ENTER", NULL, "ANS", "\\arrowright NUM", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7 + }, +}; +#define X49GP_UI_NR_KEYS (sizeof(x49gp_ui_keys) / sizeof(x49gp_ui_keys[0])) + +static const x49gp_ui_key_t x50g_ui_keys[] = +{ + { + "F1", "A", "Y=", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 0, 0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1 + }, + { + "F2", "B", "WIN", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 50, 0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2 + }, + { + "F3", "C", "GRAPH", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 99, 0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3 + }, + { + "F4", "D", "2D/3D", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 149, 0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4 + }, + { + "F5", "E", "TBLSET", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 198, 0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5 + }, + { + "F6", "F", "TABLE", NULL, NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT, + 247, 0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6 + }, + { + "APPS", "G", "FILES", "BEGIN", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 0, 44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7 + }, + { + "MODE", "H", "CUSTOM", "END", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 50, 44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5 + }, + { + "TOOL", "I", "i", "I", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 99, 44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6 + }, + { + "V\\kern-1 AR", "J", "UPDIR", "COPY", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 0, 92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7 + }, + { + "STO \\triangleright", "K", "RCL", "CUT", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 50, 92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1 + }, + { + "NXT", "L", "PREV", "PASTE", NULL, + UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW, + 99, 92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 200, 38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 164, 66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 200, 94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3 + }, + { + NULL, NULL, NULL, NULL, NULL, + UI_COLOR_SILVER, 0.0, 0, + UI_SHAPE_BUTTON_ROUND, 0.0, 0, + 236, 66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4 + }, + { + "HIST", "M", "CMD", "UNDO", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1 + }, + { + "EV\\kern-1 AL", "N", "PRG", "CHARS", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1 + }, + { + "\\tick", "O", "MTRW", "EQW", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1 + }, + { + "S\\kern-1 Y\\kern-1 M\\kern-1 B", "P", "MTH", "CAT", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1 + }, + { + "\\arrowleftdblfull", NULL, "DEL", "CLEAR", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 0.0, 0, + 238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1 + }, + { + "Y\\super x\\/super", "Q", "\\math_e\\xsuperior", "LN", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2 + }, + { + "\\radical\\overscore\\kern-7 X", "R", + "\\math_x\\twosuperior", + "\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2 + }, + { + "SIN", "S", "ASIN", "\\math_summation", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2 + }, + { + "COS", "T", "ACOS", "\\math_partialdiff", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2 + }, + { + "TAN", "U", "ATAN", "\\math_integral", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2 + }, + { + "EEX", "V", "10\\xsuperior", "LOG", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3 + }, + { + "+\\divisionslash\\minus", "W", + "\\math_notequal", + "\\math_equal", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3 + }, + { + "X", "X", + "\\math_lessequal", + "\\math_less", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3 + }, + { + "1/X", "Y", + "\\math_greaterequal", + "\\math_greater", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT, + 179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3 + }, + { + "\\divide", "Z", "ABS", "ARG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE, + 238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3 + }, + { + "ALPHA", NULL, "USER", "ENTRY", NULL, + UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 267, 46, 32, 0, 0, 0, 0, 4 + }, + { + "7", NULL, "S.SLV", "NUM.SLV", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4 + }, + { + "8", NULL, "EXP&LN", "TRIG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4 + }, + { + "9", NULL, "FINANCE", "TIME", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4 + }, + { + "\\multiply", NULL, "[ ]", "\" \"", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4 + }, + { + "\\uparrowleft", NULL, NULL, NULL, NULL, + UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 313, 46, 32, 0, 0, 0, 0, 5 + }, + { + "4", NULL, "CALC", "ALG", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5 + }, + { + "5", NULL, "MATRICES", "STAT", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5 + }, + { + "6", NULL, "CONVERT", "UNITS", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5 + }, + { + "\\minus", NULL, "( )", "_", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5 + }, + { + "\\uparrowright", NULL, NULL, NULL, NULL, + UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 359, 46, 32, 0, 0, 0, 0, 6 + }, + { + "1", NULL, "ARITH", "CMPLX", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6 + }, + { + "2", NULL, "DEF", "LIB", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6 + }, + { + "3", NULL, "\\math_numbersign", "BASE", NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6 + }, + { + "+", NULL, + "{ }", + "\\guillemotleft\\ \\guillemotright", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6 + }, + { + "ON", NULL, "CONT", "OFF", "CANCEL", + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 0, 405, 46, 32, 0, 0, 0, 0, 0 + }, + { + "0", NULL, + "\\math_infinity", + "\\math_arrowright", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7 + }, + { + "\\bullet", NULL, + ": :", + "\\math_downarrowleft", + NULL, + UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7 + }, + { + "SPC", NULL, + "\\math_pi", + "\\large_comma", + NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7 + }, + { + "ENTER", NULL, "ANS", "\\arrowright NUM", NULL, + UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD, + UI_SHAPE_BUTTON_LARGE, 0.0, 0, + 238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7 + }, +}; +#define X50G_UI_NR_KEYS (sizeof(x50g_ui_keys) / sizeof(x50g_ui_keys[0])) + +static void +x49gp_ui_color_init(GdkColor *color, u8 red, u8 green, u8 blue) +{ + color->red = (red << 8) | red; + color->green = (green << 8) | green; + color->blue = (blue << 8) | blue; +} + +static void +x49gp_ui_style_init(GtkStyle *style, GtkWidget *widget, + GdkColor *fg, GdkColor *bg) +{ + int i; + + for (i = 0; i < 5; i++) { + style->fg[i] = *fg; + style->bg[i] = *bg; + + style->text[i] = style->fg[i]; + style->base[i] = style->bg[i]; + } + + style->xthickness = 0; + style->ythickness = 0; +} + +static int +x49gp_ui_button_pixmaps_init(x49gp_t *x49gp, x49gp_ui_button_t *button, + x49gp_ui_color_t color) +{ + x49gp_ui_t *ui = x49gp->ui; + GdkPixbuf *src, *dst; + GtkStyle *style; + int i; + + style = gtk_style_new(); + x49gp_ui_style_init(style, button->button, + &ui->colors[button->key->color], + &ui->colors[UI_COLOR_BLACK]); + + for (i = 0; i < 5; i++) { + style->bg_pixmap[i] = gdk_pixmap_new(ui->window->window, + button->key->width, + button->key->height, -1); + + if (i == GTK_STATE_ACTIVE) { + if (color == UI_COLOR_SILVER) { + GError *gerror = NULL; + + src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf, + ui->kb_x_offset + button->key->x, + ui->kb_y_offset + button->key->y, + button->key->width, + button->key->height); + dst = gdk_pixbuf_copy(src); + g_object_unref(src); + + src = gdk_pixbuf_new_from_inline(sizeof(button_round), + button_round, FALSE, &gerror); + + gdk_pixbuf_composite(src, dst, + 0, 0, + button->key->width, + button->key->height, + 0.0, 0.0, 1.0, 1.0, + GDK_INTERP_HYPER, 0xff); + + g_object_unref(src); + src = dst; + } else { + src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf, + ui->kb_x_offset + button->key->x, + ui->kb_y_offset + button->key->y + 1, + button->key->width, + button->key->height); + } + } else { + src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf, + ui->kb_x_offset + button->key->x, + ui->kb_y_offset + button->key->y, + button->key->width, + button->key->height); + } + + gdk_draw_pixbuf(style->bg_pixmap[i], + ui->window->style->black_gc, + src, 0, 0, 0, 0, + button->key->width, button->key->height, + GDK_RGB_DITHER_NORMAL, 0, 0); + + g_object_unref(src); + } + + gtk_widget_set_style(button->button, style); + return 0; +} + +static void +x49gp_ui_symbol_path(cairo_t *cr, double size, + double xoffset, double yoffset, + const x49gp_symbol_t *symbol) +{ + const symbol_path_t *path; + const cairo_path_data_t *data; + int i; + + path = symbol->path; + if (NULL == path) { + return; + } + + cairo_move_to(cr, xoffset, yoffset); + + for (i = 0; i < path->num_data; i += path->data[i].header.length) { + data = &path->data[i]; + + switch (data->header.type) { + case CAIRO_PATH_MOVE_TO: + cairo_rel_move_to(cr, size * data[1].point.x, + -size * data[1].point.y); + break; + case CAIRO_PATH_LINE_TO: + cairo_rel_line_to(cr, size * data[1].point.x, + -size * data[1].point.y); + break; + case CAIRO_PATH_CURVE_TO: + cairo_rel_curve_to(cr, size * data[1].point.x, + -size * data[1].point.y, + size * data[2].point.x, + -size * data[2].point.y, + size * data[3].point.x, + -size * data[3].point.y); + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path(cr); + break; + } + } +} + +static void +x49gp_ui_draw_symbol(cairo_t *cr, GdkColor *color, double size, + double line_width, gboolean fill, + double xoffset, double yoffset, + const x49gp_symbol_t *symbol) +{ + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + cairo_set_line_width(cr, line_width); + cairo_set_source_rgb(cr, ((double) color->red) / 65535.0, + ((double) color->green) / 65535.0, + ((double) color->blue) / 65535.0); + + x49gp_ui_symbol_path(cr, size, xoffset, yoffset, symbol); + + if (fill) { + cairo_fill(cr); + } else { + cairo_stroke(cr); + } +} + +static int +x49gp_ui_lookup_glyph(const char *name, int namelen, gunichar *glyph) +{ + int i; + + for (i = 0; i < NR_GLYPHNAMES; i++) { + if ((strlen(x49gp_glyphs[i].name) == namelen) && + !strncmp(x49gp_glyphs[i].name, name, namelen)) { + if (glyph) + *glyph = x49gp_glyphs[i].unichar; + return 1; + } + } + + return 0; +} + +static int +x49gp_text_strlen(const char *text) +{ + const char *p, *q; + char c; + int namelen; + int n = 0; + + p = text; + while ((c = *p++)) { + if (c != '\\') { + n++; + continue; + } + + q = p; + while (*q) { + if ((*q == '\\') || (*q == ' ')) + break; + q++; + } + if (q == p) { + n++; + p++; + continue; + } + namelen = q - p; + if (*q == ' ') + q++; + + if (symbol_lookup_glyph_by_name(p, namelen, NULL)) { + p = q; + n++; + continue; + } + + if (x49gp_ui_lookup_glyph(p, namelen, NULL)) { + p = q; + n++; + continue; + } + + /* + * Insert symbol .notdef here... + */ + p = q; + n++; + } + + return n; +} + +static int +x49gp_text_to_ucs4(const char *text, gunichar **ucs4p) +{ + const char *p, *q; + gunichar glyph; + gunichar *ucs4; + char c; + int namelen; + int i, n; + + n = x49gp_text_strlen(text); + if (n <= 0) + return n; + + ucs4 = malloc(n * sizeof(gunichar)); + + i = 0; + + p = text; + while ((c = *p++)) { + if (i == n) { + free(ucs4); + return -1; + } + + if (c != '\\') { + ucs4[i++] = c; + continue; + } + + q = p; + while (*q) { + if ((*q == '\\') || (*q == ' ')) + break; + q++; + } + if (q == p) { + ucs4[i++] = *p++; + continue; + } + namelen = q - p; + if (*q == ' ') + q++; + + if (symbol_lookup_glyph_by_name(p, namelen, &glyph)) { + ucs4[i++] = glyph; + p = q; + continue; + } + + if (x49gp_ui_lookup_glyph(p, namelen, &glyph)) { + ucs4[i++] = glyph; + p = q; + continue; + } + + /* + * Insert symbol .notdef here... + */ + ucs4[i++] = 0xe000; + p = q; + } + + *ucs4p = ucs4; + return n; +} + +static void +x49gp_ui_vtext_path(cairo_t *cr, const char *family, double size, + double x, double y, int n, va_list ap) +{ + cairo_text_extents_t extents; + cairo_font_weight_t weight; + cairo_font_slant_t slant; + const x49gp_symbol_t *symbol; + const char *text; + gunichar *ucs4; + char out[8]; + int bytes; + int i, j, len; + + for (i = 0; i < n; i++) { + slant = va_arg(ap, cairo_font_slant_t); + weight = va_arg(ap, cairo_font_weight_t); + text = va_arg(ap, const char *); + + cairo_select_font_face(cr, family, slant, weight); + cairo_set_font_size(cr, size); + + ucs4 = NULL; + len = x49gp_text_to_ucs4(text, &ucs4); + if (len <= 0) { + continue; + } + + for (j = 0; j < len; j++) { + if (g_unichar_type(ucs4[j]) == G_UNICODE_PRIVATE_USE) { + /* + * Draw Symbol, Increment x... + */ + symbol = symbol_get_by_glyph(ucs4[j]); + if (NULL == symbol) + symbol = symbol_get_by_glyph(0xe000); + + size *= symbol->prescale; + + x49gp_ui_symbol_path(cr, size, x, y, symbol); + + x += size * symbol->x_advance; + y -= size * symbol->y_advance; + + size *= symbol->postscale; + + if (symbol->prescale * symbol->postscale != 1.) + cairo_set_font_size(cr, size); + + continue; + } + + bytes = g_unichar_to_utf8(ucs4[j], out); + out[bytes] = '\0'; + + cairo_text_extents(cr, out, &extents); + + cairo_move_to(cr, x, y); + + cairo_text_path(cr, out); + + x += extents.x_advance; + y += extents.y_advance; + } + + free(ucs4); + } +} + +static void +x49gp_ui_text_size(cairo_t *cr, const char *family, double size, + double *x_bearing, double *y_bearing, + double *width, double *height, + double *ascent, double *descent, + int n, ...) +{ + va_list ap; + cairo_font_extents_t font_extents; + cairo_font_weight_t weight; + cairo_font_slant_t slant; + double x1, y1, x2, y2, a, d; + const char *text; + int i; + + if (n < 1) + return; + + va_start(ap, n); + + x49gp_ui_vtext_path(cr, family, size, 0.0, 0.0, n, ap); + + cairo_fill_extents(cr, &x1, &y1, &x2, &y2); + + if (y2 < 0.0) + y2 = 0.0; + + a = 0.0; + d = 0.0; + + for (i = 0; i < n; i++) { + slant = va_arg(ap, cairo_font_slant_t); + weight = va_arg(ap, cairo_font_weight_t); + text = va_arg(ap, const char *); + + cairo_select_font_face(cr, family, slant, weight); + cairo_set_font_size(cr, size); + + cairo_font_extents(cr, &font_extents); + + /* + * Cairo seems to return overall height in ascent, + * so fix this by calculating ascent = height - descent. + */ + if (font_extents.ascent - font_extents.descent > a) + a = font_extents.ascent - font_extents.descent; + if (font_extents.descent > -d) + d = -font_extents.descent; + } + + *x_bearing = x1; + *y_bearing = y2; + *width = x2 - x1; + *height = y2 - y1; + *ascent = a; + *descent = d; + + va_end(ap); +} + +static void +x49gp_ui_draw_text(cairo_t *cr, GdkColor *color, + const char *family, double size, double line_width, + int xoffset, int yoffset, int n, ...) +{ + va_list ap; + + if (n < 1) + return; + + va_start(ap, n); + + cairo_set_line_width(cr, line_width); + cairo_set_source_rgb(cr, ((double) color->red) / 65535.0, + ((double) color->green) / 65535.0, + ((double) color->blue) / 65535.0); + + x49gp_ui_vtext_path(cr, family, size, xoffset, yoffset, n, ap); + + if (line_width == 0.0) + cairo_fill(cr); + else + cairo_stroke(cr); + + va_end(ap); +} + +#if 0 +static void +x49gp_ui_dump_path(cairo_t *cr, const char *family, int n, ...) +{ + va_list ap; + const cairo_path_t *path; + const cairo_path_data_t *data; + int i; + + if (n < 1) + return; + + va_start(ap, n); + + x49gp_ui_vtext_path(cr, family, 1000.0, 0.0, 0.0, n, ap); + + path = cairo_copy_path(cr); + if (NULL == path) { + return; + } + cairo_new_path(cr); + + for (i = 0; i < path->num_data; i += path->data[i].header.length) { + data = &path->data[i]; + + switch (data->header.type) { + case CAIRO_PATH_MOVE_TO: + printf("path: move to %4.0f %4.0f\n", + data[1].point.x, -data[1].point.y); + break; + case CAIRO_PATH_LINE_TO: + printf("path: line to %4.0f %4.0f\n", + data[1].point.x, -data[1].point.y); + break; + case CAIRO_PATH_CURVE_TO: + printf("path: curve to %4.0f %4.0f\n" + " %4.0f %4.0f\n" + " %4.0f %4.0f\n", + data[1].point.x, -data[1].point.y, + data[2].point.x, -data[2].point.y, + data[3].point.x, -data[3].point.y); + break; + case CAIRO_PATH_CLOSE_PATH: + printf("path: close path\n"); + break; + } + } + + va_end(ap); +} +#endif + +static unsigned char +bitmap_font_lookup_glyph(const bitmap_font_t *font, + const char *name, int namelen) +{ + int i; + + for (i = 0; font->glyphs[i].name; i++) { + if ((strlen(font->glyphs[i].name) == namelen) && + !strncmp(font->glyphs[i].name, name, namelen)) { + return i; + } + } + + return 0; +} + +static unsigned char +bitmap_font_lookup_ascii(const bitmap_font_t *font, char c) +{ + int namelen = 0; + char *name; + + switch (c) { + case ' ': name = "space"; break; + case '!': name = "exclam"; break; + case '"': name = "quotedbl"; break; + case '#': name = "numbersign"; break; + case '$': name = "dollar"; break; + case '%': name = "percent"; break; + case '&': name = "ampersand"; break; + case '(': name = "parenleft"; break; + case ')': name = "parenright"; break; + case '*': name = "asterisk"; break; + case '+': name = "plus"; break; + case ',': name = "comma"; break; + case '-': name = "hyphen"; break; + case '.': name = "period"; break; + case '/': name = "slash"; break; + case '0': name = "zero"; break; + case '1': name = "one"; break; + case '2': name = "two"; break; + case '3': name = "three"; break; + case '4': name = "four"; break; + case '5': name = "five"; break; + case '6': name = "six"; break; + case '7': name = "seven"; break; + case '8': name = "eight"; break; + case '9': name = "nine"; break; + case ':': name = "colon"; break; + case ';': name = "semicolon"; break; + case '<': name = "less"; break; + case '=': name = "equal"; break; + case '>': name = "greater"; break; + case '?': name = "question"; break; + case '@': name = "at"; break; + case '[': name = "bracketleft"; break; + case '\\': name = "backslash"; break; + case ']': name = "bracketright"; break; + case '^': name = "asciicircum"; break; + case '_': name = "underscore"; break; + case '`': name = "quoteleft"; break; + case '{': name = "braceleft"; break; + case '|': name = "bar"; break; + case '}': name = "braceright"; break; + case '~': name = "asciitilde"; break; + default: + name = &c; + namelen = 1; + break; + } + + if (0 == namelen) + namelen = strlen(name); + + return bitmap_font_lookup_glyph(font, name, namelen); +} + +static int +bitmap_font_strlen(const char *text) +{ + const char *p, *q; + char c; + int n = 0; + + p = text; + while ((c = *p++)) { + if (c != '\\') { + n++; + continue; + } + + q = p; + while (*q) { + if ((*q == '\\') || (*q == ' ')) + break; + q++; + } + if (q == p) { + n++; + p++; + continue; + } + if (*q == ' ') + q++; + + n++; + p = q; + } + + return n; +} + +static int +bitmap_font_text_to_glyphs(const bitmap_font_t *font, + const char *text, unsigned char **glyphp) +{ + unsigned char *glyphs; + const char *p, *q; + unsigned char c; + int namelen; + int i, n; + + n = bitmap_font_strlen(text); + if (n <= 0) + return n; + + glyphs = malloc(n); + + i = 0; + + p = text; + while ((c = *p++)) { + if (i == n) { + free(glyphs); + return -1; + } + + if (c != '\\') { + glyphs[i++] = bitmap_font_lookup_ascii(font, c); + continue; + } + + q = p; + while (*q) { + if ((*q == '\\') || (*q == ' ')) + break; + q++; + } + if (q == p) { + glyphs[i++] = bitmap_font_lookup_ascii(font, *p++); + continue; + } + namelen = q - p; + if (*q == ' ') + q++; + + glyphs[i++] = bitmap_font_lookup_glyph(font, p, namelen); + p = q; + } + + *glyphp = glyphs; + return n; + +} + +static void +bitmap_font_text_size(const bitmap_font_t *font, const char *text, + int *width, int *height, int *ascent, int *descent) +{ + const bitmap_glyph_t *glyph; + unsigned char *glyphs; + int i, n, w, a, d; + + w = 0; + a = 0; + d = 0; + + n = bitmap_font_text_to_glyphs(font, text, &glyphs); + + for (i = 0; i < n; i++) { + glyph = &font->glyphs[glyphs[i]]; + + w += glyph->width; + + if (glyph->ascent > a) + a = glyph->ascent; + if (glyph->descent < d) + d = glyph->descent; + } + + *width = w - 1; + *height = font->ascent - font->descent; + *ascent = a; + *descent = d; + + if (n > 0) { + free(glyphs); + } +} + +static void +bitmap_font_draw_text(GdkDrawable *drawable, GdkColor *color, + const bitmap_font_t *font, + int x, int y, const char *text) +{ + const bitmap_glyph_t *glyph; + unsigned char *glyphs; + GdkBitmap *bitmap; + GdkGC *gc; + int i, n, w, h; + + gc = gdk_gc_new(drawable); + gdk_gc_set_rgb_fg_color(gc, color); + + n = bitmap_font_text_to_glyphs(font, text, &glyphs); + + for (i = 0; i < n; i++) { + glyph = &font->glyphs[glyphs[i]]; + + w = glyph->width - glyph->kern; + h = glyph->ascent - glyph->descent; + + if (w <= 0 || h <= 0) { + x += glyph->width; + continue; + } + + bitmap = gdk_bitmap_create_from_data(NULL, (char *) glyph->bits, w, h); + + gdk_gc_set_ts_origin(gc, x + glyph->kern, + y + font->ascent - glyph->ascent); + gdk_gc_set_stipple(gc, bitmap); + gdk_gc_set_fill(gc, GDK_STIPPLED); + + gdk_draw_rectangle(drawable, gc, TRUE, x + glyph->kern, + y + font->ascent - glyph->ascent, w, h); + + g_object_unref(bitmap); + + x += glyph->width; + } + + g_object_unref(gc); + + if (n > 0) { + free(glyphs); + } +} + +static gboolean +x49gp_ui_button_press(GtkWidget *widget, GdkEventButton *event, + gpointer user_data) +{ + x49gp_ui_button_t *button = user_data; + const x49gp_ui_key_t *key = button->key; + x49gp_t *x49gp = button->x49gp; + +#ifdef DEBUG_X49GP_UI +fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button); +#endif + + if (event->type != GDK_BUTTON_PRESS) + return FALSE; + + switch (event->button) { + case 1: + button->down = TRUE; + break; + case 3: + if (!button->down) { + gtk_button_pressed(GTK_BUTTON(button->button)); + } + button->down = TRUE; + button->hold = TRUE; + break; + default: + return TRUE; + } + +#ifdef DEBUG_X49GP_UI + printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__, + event->button, + button->key->column, button->key->row, button->key->eint); +#endif + + if (key->rowbit) { + s3c2410_io_port_g_set_bit(x49gp, key->eint, 1); + x49gp->keybycol[key->column] |= key->rowbit; + x49gp->keybyrow[key->row] |= key->columnbit; + } else { + s3c2410_io_port_f_set_bit(x49gp, key->eint, 1); + } + + return FALSE; +} + +static gboolean +x49gp_ui_button_release(GtkWidget *widget, GdkEventButton *event, + gpointer user_data) +{ + x49gp_ui_button_t *button = user_data; + x49gp_t *x49gp = button->x49gp; + x49gp_ui_t *ui = x49gp->ui; + const x49gp_ui_key_t *key; + GtkButton *gtkbutton; + int i; + + if (event->type != GDK_BUTTON_RELEASE) + return FALSE; + + switch (event->button) { + case 1: + break; + default: + return TRUE; + } + + for (i = 0; i < ui->nr_buttons; i++) { + button = &ui->buttons[i]; + + if (! button->down) + continue; + +#ifdef DEBUG_X49GP_UI + printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__, + event->button, + button->key->column, button->key->row, button->key->eint); +#endif + + button->down = FALSE; + button->hold = FALSE; + + gtkbutton = GTK_BUTTON(button->button); + + if (button != user_data) + gtkbutton->in_button = FALSE; + gtk_button_released(gtkbutton); + + key = button->key; + + if (key->rowbit) { + s3c2410_io_port_g_set_bit(x49gp, key->eint, 0); + x49gp->keybycol[key->column] &= ~(key->rowbit); + x49gp->keybyrow[key->row] &= ~(key->columnbit); + } else { + s3c2410_io_port_f_set_bit(x49gp, key->eint, 0); + } + } + + return FALSE; +} + +static gboolean +x49gp_ui_button_leave(GtkWidget *widget, GdkEventCrossing *event, + gpointer user_data) +{ + x49gp_ui_button_t *button = user_data; + + if (event->type != GDK_LEAVE_NOTIFY) + return FALSE; + + if (!button->hold) + return FALSE; + + return TRUE; +} + +static gboolean +x49gp_ui_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) +{ + x49gp_t *x49gp = user_data; + x49gp_ui_t *ui = x49gp->ui; + x49gp_ui_button_t *button; + GdkEventButton bev; + gboolean save_in; + int index; + +#ifdef DEBUG_X49GP_UI +fprintf(stderr, "%s:%u: type %u, keyval %04x\n", __FUNCTION__, __LINE__, event->type, event->keyval); +#endif + + switch (event->keyval) { + case GDK_A: case GDK_a: case GDK_F1: index = 0; break; + case GDK_B: case GDK_b: case GDK_F2: index = 1; break; + case GDK_C: case GDK_c: case GDK_F3: index = 2; break; + case GDK_D: case GDK_d: case GDK_F4: index = 3; break; + case GDK_E: case GDK_e: case GDK_F5: index = 4; break; + case GDK_F: case GDK_f: case GDK_F6: index = 5; break; + case GDK_G: case GDK_g: index = 6; break; + case GDK_H: case GDK_h: index = 7; break; + case GDK_I: case GDK_i: index = 8; break; + case GDK_J: case GDK_j: index = 9; break; + case GDK_K: case GDK_k: index = 10; break; + case GDK_L: case GDK_l: index = 11; break; + case GDK_Up: case GDK_KP_Up: index = 12; break; + case GDK_Left: case GDK_KP_Left: index = 13; break; + case GDK_Down: case GDK_KP_Down: index = 14; break; + case GDK_Right: case GDK_KP_Right: index = 15; break; + case GDK_M: case GDK_m: index = 16; break; + case GDK_N: case GDK_n: index = 17; break; + case GDK_O: case GDK_o: + case GDK_apostrophe: index = 18; break; + case GDK_P: case GDK_p: index = 19; break; + case GDK_BackSpace: case GDK_Delete: + case GDK_KP_Delete: index = 20; break; + case GDK_Q: case GDK_q: index = 21; break; + case GDK_R: case GDK_r: index = 22; break; + case GDK_S: case GDK_s: index = 23; break; + case GDK_T: case GDK_t: index = 24; break; + case GDK_U: case GDK_u: index = 25; break; + case GDK_V: case GDK_v: index = 26; break; + case GDK_W: case GDK_w: index = 27; break; + case GDK_X: case GDK_x: index = 28; break; + case GDK_Y: case GDK_y: index = 29; break; + case GDK_Z: case GDK_z: + case GDK_slash: case GDK_KP_Divide: index = 30; break; +#ifdef __APPLE__ + case GDK_Tab: index = 31; break; +#else + case GDK_Tab: index = 31; break; + case GDK_Alt_L: case GDK_Alt_R: + case GDK_Meta_L: case GDK_Meta_R: + case GDK_Mode_switch: index = 31; break; +#endif + case GDK_7: case GDK_KP_7: index = 32; break; + case GDK_8: case GDK_KP_8: index = 33; break; + case GDK_9: case GDK_KP_9: index = 34; break; + case GDK_multiply: case GDK_backslash: + case GDK_KP_Multiply: index = 35; break; + case GDK_Shift_L: index = 36; break; + case GDK_4: case GDK_KP_4: index = 37; break; + case GDK_5: case GDK_KP_5: index = 38; break; + case GDK_6: case GDK_KP_6: index = 39; break; + case GDK_minus: case GDK_KP_Subtract: index = 40; break; + case GDK_Shift_R: case GDK_Control_L: index = 41; break; + case GDK_1: case GDK_KP_1: index = 42; break; + case GDK_2: case GDK_KP_2: index = 43; break; + case GDK_3: case GDK_KP_3: index = 44; break; + case GDK_plus: case GDK_equal: + case GDK_KP_Add: index = 45; break; + case GDK_Escape: index = 46; break; + case GDK_0: case GDK_KP_0: index = 47; break; + case GDK_period: case GDK_comma: + case GDK_KP_Decimal: index = 48; break; + case GDK_space: case GDK_KP_Space: index = 49; break; + case GDK_Return: case GDK_KP_Enter: index = 50; break; + default: + return FALSE; + } + + button = &ui->buttons[index]; + + memset(&bev, 0, sizeof(GdkEventButton)); + + bev.time = event->time; + bev.button = 1; + bev.state = event->state; + + save_in = GTK_BUTTON(button->button)->in_button; + + switch (event->type) { + case GDK_KEY_PRESS: + bev.type = GDK_BUTTON_PRESS; + x49gp_ui_button_press(button->button, &bev, button); + GTK_BUTTON(button->button)->in_button = TRUE; + gtk_button_pressed(GTK_BUTTON(button->button)); + GTK_BUTTON(button->button)->in_button = save_in; + break; + case GDK_KEY_RELEASE: + bev.type = GDK_BUTTON_RELEASE; + GTK_BUTTON(button->button)->in_button = TRUE; + gtk_button_released(GTK_BUTTON(button->button)); + GTK_BUTTON(button->button)->in_button = save_in; + x49gp_ui_button_release(button->button, &bev, button); + break; + default: + return FALSE; + } + + return TRUE; +} + +static int +x49gp_button_expose_event(GtkWidget *widget, GdkEventExpose *event, + gpointer user_data) +{ + x49gp_ui_button_t *button = user_data; + int x, y; + + x = widget->allocation.x; + y = widget->allocation.y; + + if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE) + y -= 1; + + gdk_draw_drawable(widget->window, widget->style->black_gc, + button->pixmap, 0, 0, x, y, + widget->allocation.width, widget->allocation.height); + + return FALSE; +} + +static void +x49gp_button_realize(GtkWidget *widget, gpointer user_data) +{ + x49gp_ui_button_t *button = user_data; + x49gp_ui_t *ui = button->x49gp->ui; + const x49gp_ui_key_t *key = button->key; + cairo_t *cr; + double xoff, yoff, width, height, ascent, descent; + unsigned int w, h; + int xoffset, yoffset, x, y; + + xoffset = widget->allocation.x; + yoffset = widget->allocation.y; + w = widget->allocation.width; + h = widget->allocation.height; + + button->pixmap = gdk_pixmap_new(widget->style->bg_pixmap[0], w, h, -1); + + gdk_draw_drawable(button->pixmap, widget->style->black_gc, + widget->style->bg_pixmap[0], + xoffset, yoffset, + 0, 0, button->key->width, button->key->height); + + xoffset += 2; + yoffset += 2; + w -= 4; + h -= 4; + + cr = gdk_cairo_create(button->pixmap); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + +#if 0 /* Layout Debug */ + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr, xoffset, yoffset); + cairo_line_to(cr, xoffset + w - 1, yoffset); + cairo_line_to(cr, xoffset + w - 1, yoffset + h - 1); + cairo_line_to(cr, xoffset, yoffset + h - 1); + cairo_close_path(cr); + cairo_stroke(cr); +#endif + + if (key->letter) { + x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->letter_size, + &xoff, &yoff, &width, &height, &ascent, &descent, + 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight, + key->letter); + + switch (key->layout) { + case UI_LAYOUT_LEFT: + default: + x = (int) floor(w - 1.0 - width - xoff + 0.5); + y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5); + w -= width; + break; + case UI_LAYOUT_LEFT_NO_SPACE: + x = (int) floor(w - 1.0 - width - xoff + 0.5); + y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5); + break; + case UI_LAYOUT_BELOW: + x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5); + y = (int) h - 1.0; + h -= ascent; + break; + } + + x49gp_ui_draw_text(cr, &ui->colors[UI_COLOR_YELLOW], + X49GP_UI_NORMAL_FONT, key->letter_size, 0.0, + x + xoffset, y + yoffset, + 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight, + key->letter); + } + + x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->font_size, + &xoff, &yoff, &width, &height, &ascent, &descent, + 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight, + key->label); + + x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5); + y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5); + + x49gp_ui_draw_text(cr, &widget->style->text[0], + X49GP_UI_NORMAL_FONT, key->font_size, 0.0, + x + xoffset, y + yoffset, + 1, CAIRO_FONT_SLANT_NORMAL, key->font_weight, + key->label); + + cairo_destroy(cr); +} + +static int +x49gp_lcd_expose_event(GtkWidget *widget, GdkEventExpose *event, + gpointer user_data) +{ + x49gp_t *x49gp = user_data; + x49gp_ui_t *ui = x49gp->ui; + GdkRectangle *rects; + int i, n; + + gdk_region_get_rectangles(event->region, &rects, &n); + for (i = 0; i < n; i++) { + gdk_draw_drawable(widget->window, widget->style->black_gc, + ui->lcd_pixmap, + rects[i].x, rects[i].y, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + } + g_free(rects); + + return FALSE; +} + +static int +x49gp_lcd_configure_event(GtkWidget *widget, GdkEventConfigure *event, + gpointer user_data) +{ + x49gp_t *x49gp = user_data; + x49gp_ui_t *ui = x49gp->ui; + + if (NULL != ui->lcd_pixmap) { + return FALSE; + } + + ui->ann_left = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_left_bits, + ann_left_width, + ann_left_height); + ui->ann_right = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_right_bits, + ann_right_width, + ann_right_height); + ui->ann_alpha = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_alpha_bits, + ann_alpha_width, + ann_alpha_height); + ui->ann_battery = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_battery_bits, + ann_battery_width, + ann_battery_height); + ui->ann_busy = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_busy_bits, + ann_busy_width, + ann_busy_height); + ui->ann_io = gdk_bitmap_create_from_data(ui->lcd_canvas->window, + (char *) ann_io_bits, + ann_io_width, + ann_io_height); + + ui->ann_left_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_left_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_left_gc, 11, 0); + gdk_gc_set_stipple(ui->ann_left_gc, ui->ann_left); + gdk_gc_set_fill(ui->ann_left_gc, GDK_STIPPLED); + + ui->ann_right_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_right_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_right_gc, 56, 0); + gdk_gc_set_stipple(ui->ann_right_gc, ui->ann_right); + gdk_gc_set_fill(ui->ann_right_gc, GDK_STIPPLED); + + ui->ann_alpha_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_alpha_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_alpha_gc, 101, 0); + gdk_gc_set_stipple(ui->ann_alpha_gc, ui->ann_alpha); + gdk_gc_set_fill(ui->ann_alpha_gc, GDK_STIPPLED); + + ui->ann_battery_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_battery_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_battery_gc, 146, 0); + gdk_gc_set_stipple(ui->ann_battery_gc, ui->ann_battery); + gdk_gc_set_fill(ui->ann_battery_gc, GDK_STIPPLED); + + ui->ann_busy_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_busy_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_busy_gc, 191, 0); + gdk_gc_set_stipple(ui->ann_busy_gc, ui->ann_busy); + gdk_gc_set_fill(ui->ann_busy_gc, GDK_STIPPLED); + + ui->ann_io_gc = gdk_gc_new(ui->lcd_canvas->window); + gdk_gc_copy(ui->ann_io_gc, widget->style->black_gc); + gdk_gc_set_ts_origin(ui->ann_io_gc, 236, 0); + gdk_gc_set_stipple(ui->ann_io_gc, ui->ann_io); + gdk_gc_set_fill(ui->ann_io_gc, GDK_STIPPLED); + + + ui->lcd_pixmap = gdk_pixmap_new(ui->lcd_canvas->window, + ui->lcd_width, ui->lcd_height, -1); + +#if 0 /* Debug Symbols on LCD screen ;) */ +{ + cairo_t *cr; + + cr = gdk_cairo_create(ui->bg_pixmap); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + +#if 1 + x49gp_ui_draw_text(cr, &widget->style->black, + X49GP_UI_NORMAL_FONT, 100.0, 1.0, + ui->lcd_x_offset + 10, ui->lcd_y_offset + 160, + 1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD, + "\\arrowleftdblfull"); +#else + x49gp_ui_dump_path(cr, X49GP_UI_NORMAL_FONT, + 1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD, + "\\arrowleftdblfull"); +#endif + + cairo_destroy(cr); +} +#endif + + gdk_draw_drawable(ui->lcd_pixmap, widget->style->black_gc, + ui->bg_pixmap, ui->lcd_x_offset, ui->lcd_y_offset, + 0, 0, ui->lcd_width, ui->lcd_height); + + return FALSE; +} + +static int +x49gp_window_configure_event(GtkWidget *widget, GdkEventConfigure *event, + gpointer user_data) +{ + x49gp_t *x49gp = user_data; + x49gp_ui_t *ui = x49gp->ui; + const x49gp_ui_key_t *key; + cairo_t *cr; + int left_color; + int right_color; + int below_color; + int xl, xr, a; + int wl = 0, wr = 0; + int hl = 0, hr = 0; + int dl = 0, dr = 0; + int i; + + if (NULL != ui->bg_pixmap) { + return FALSE; + } + + ui->bg_pixmap = gdk_pixmap_new(widget->window, + ui->width, ui->height, -1); + + gdk_draw_pixbuf(ui->bg_pixmap, widget->style->black_gc, + ui->bg_pixbuf, 0, 0, 0, 0, ui->width, ui->height, + GDK_RGB_DITHER_NORMAL, 0, 0); + + cr = gdk_cairo_create(ui->bg_pixmap); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + + switch (ui->calculator) { + default: + ui->calculator = UI_CALCULATOR_HP49GP; + /* fall through */ + + case UI_CALCULATOR_HP49GP: + x49gp_ui_draw_text(cr, &widget->style->black, + X49GP_UI_NORMAL_FONT, 15.0, 0.0, + 38, 42, 2, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD, + "hp", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL, + " 49g+"); + + x49gp_ui_draw_text(cr, &widget->style->black, + X49GP_UI_NORMAL_FONT, 13.0, 0.0, + 38, 56, 1, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL, + "graphing calculator"); + + x49gp_ui_draw_symbol(cr, &widget->style->black, 10.0, 0.0, TRUE, + 138, 25, symbol_get_by_name("triangleup")); + + left_color = UI_COLOR_GREEN; + right_color = UI_COLOR_RED; + below_color = UI_COLOR_BLACK; + break; + + case UI_CALCULATOR_HP50G: + x49gp_ui_draw_text(cr, &widget->style->white, + X49GP_UI_NORMAL_FONT, 15.0, 0.0, + 38, 42, 2, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL, + "HP", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL, + " 50g"); + + x49gp_ui_draw_text(cr, &widget->style->white, + X49GP_UI_NORMAL_FONT, 13.0, 0.0, + 38, 56, 1, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL, + "Graphing Calculator"); + + x49gp_ui_draw_symbol(cr, &widget->style->white, 10.0, 0.0, TRUE, + 168, 25, symbol_get_by_name("triangleup")); + + left_color = UI_COLOR_WHITE; + right_color = UI_COLOR_ORANGE; + below_color = UI_COLOR_BLUE; + break; + } + + cairo_destroy(cr); + + for (i = 0; i < ui->nr_buttons; i++) { + key = &x49gp_ui_keys[i]; + key = &x50g_ui_keys[i]; + + if (key->left) { + bitmap_font_text_size(&tiny_font, key->left, &wl, &hl, &a, &dl); + if (!key->right) { + xl = key->x + (key->width - wl) / 2; + bitmap_font_draw_text(ui->bg_pixmap, + &ui->colors[left_color], + &tiny_font, + ui->kb_x_offset + xl, + ui->kb_y_offset + key->y - hl + dl + 1, + key->left); + } + } + + if (key->right) { + bitmap_font_text_size(&tiny_font, key->right, &wr, &hr, &a, &dr); + if (!key->left) { + xr = key->x + (key->width - wr) / 2; + bitmap_font_draw_text(ui->bg_pixmap, + &ui->colors[right_color], + &tiny_font, + ui->kb_x_offset + xr, + ui->kb_y_offset + key->y - hr + dr + 1, + key->right); + } + } + + if (key->left && key->right) { + xl = key->x; + xr = key->x + key->width - 1 - wr; + + if (wl + wr > key->width - 4) { + xl += (key->width - 4 - (wl + wr)) / 2; + xr -= (key->width - 4 - (wl + wr)) / 2; + } + + bitmap_font_draw_text(ui->bg_pixmap, + &ui->colors[left_color], + &tiny_font, + ui->kb_x_offset + xl, + ui->kb_y_offset + key->y - hl + dl + 1, + key->left); + + bitmap_font_draw_text(ui->bg_pixmap, + &ui->colors[right_color], + &tiny_font, + ui->kb_x_offset + xr, + ui->kb_y_offset + key->y - hr + dr + 1, + key->right); + } + + if (key->below) { + bitmap_font_text_size(&tiny_font, key->below, &wl, &hl, &a, &dl); + xl = key->x + (key->width - wl) / 2; + + bitmap_font_draw_text(ui->bg_pixmap, + &ui->colors[below_color], + &tiny_font, + ui->kb_x_offset + xl, + ui->kb_y_offset + key->y + key->height + 2, + key->below); + } + +#if 0 /* Debug Button Layout */ + gdk_draw_rectangle(ui->bg_pixmap, ui->window->style->white_gc, + FALSE, + ui->kb_x_offset + key->x, + ui->kb_y_offset + key->y, + key->width, key->height); +#endif + } + + gdk_window_set_back_pixmap(widget->window, ui->bg_pixmap, FALSE); + + return FALSE; +} + +static gboolean +x49gp_window_button_press(GtkWidget *widget, GdkEventButton *event, + gpointer user_data) +{ +#ifdef DEBUG_X49GP_UI +fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button); +#endif + + gdk_window_focus(widget->window, event->time); + gdk_window_raise(widget->window); + + if (event->type != GDK_BUTTON_PRESS) + return FALSE; + + if (event->button != 1) + return FALSE; + + gdk_window_begin_move_drag(widget->window, event->button, + event->x_root, event->y_root, + event->time); + + return FALSE; +} + +static void +x49gp_ui_quit(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + x49gp_t *x49gp = user_data; + + x49gp->arm_exit++; +} + +static void +x49gp_ui_place_at(x49gp_t *x49gp, GtkFixed *fixed, GtkWidget *widget, + gint x, gint y, gint width, gint height) +{ + gtk_widget_set_size_request(widget, width, height); + gtk_fixed_put(fixed, widget, x, y); +} + +static int +gui_init(x49gp_module_t *module) +{ + x49gp_t *x49gp = module->x49gp; + x49gp_ui_t *ui; + + ui = malloc(sizeof(x49gp_ui_t)); + if (NULL == ui) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + x49gp->progname, __FUNCTION__, __LINE__); + return -ENOMEM; + } + memset(ui, 0, sizeof(x49gp_ui_t)); + + ui->nr_buttons = X49GP_UI_NR_KEYS; + ui->buttons = malloc(ui->nr_buttons * sizeof(x49gp_ui_button_t)); + if (NULL == ui->buttons) { + fprintf(stderr, "%s: %s:%u: Out of memory\n", + x49gp->progname, __FUNCTION__, __LINE__); + free(ui); + return -ENOMEM; + } + memset(ui->buttons, 0, ui->nr_buttons * sizeof(x49gp_ui_button_t)); + + module->user_data = ui; + x49gp->ui = ui; + + return 0; +} + +static int +gui_exit(x49gp_module_t *module) +{ + return 0; +} + +static int +gui_reset(x49gp_module_t *module, x49gp_reset_t reset) +{ + return 0; +} + +static int +gui_load(x49gp_module_t *module, GKeyFile *keyfile) +{ + x49gp_t *x49gp = module->x49gp; + x49gp_ui_t *ui = module->user_data; + x49gp_ui_button_t *button; + const x49gp_ui_key_t *key; + GError *gerror = NULL; + GdkBitmap *shape; + char *imagefile; + char *name; + int i; + + imagefile = x49gp_module_get_filename(module, keyfile, "image"); + x49gp_module_get_string(module, keyfile, "name", "hp49g+", &name); + + if (!strcmp(name, "hp49g+")) { + ui->calculator = UI_CALCULATOR_HP49GP; + } else if (!strcmp(name, "hp50g")) { + ui->calculator = UI_CALCULATOR_HP50G; + } else { + ui->calculator = 0; + } + + gdk_pixbuf_get_file_info(imagefile, &ui->width, &ui->height); + + ui->lcd_width = 131 * 2; + ui->lcd_top_margin = 16; + ui->lcd_height = 80 * 2 + ui->lcd_top_margin; + + ui->lcd_x_offset = (ui->width - ui->lcd_width) / 2; + ui->lcd_y_offset = 69; + + ui->kb_x_offset = 36; + ui->kb_y_offset = 301; + + ui->bg_pixbuf = gdk_pixbuf_new_from_file(imagefile, &gerror); + + + ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set(ui->window, "can-focus", TRUE, NULL); + gtk_widget_set(ui->window, "accept-focus", TRUE, NULL); + gtk_widget_set(ui->window, "focus-on-map", TRUE, NULL); + gtk_widget_set(ui->window, "resizable", FALSE, NULL); + gtk_window_set_decorated(GTK_WINDOW(ui->window), FALSE); + + gtk_widget_set_name(ui->window, name); + gtk_window_set_title(GTK_WINDOW(ui->window), name); + +// gtk_window_set_icon(GTK_WINDOW(ui->window), ui->bg_pixbuf); + + gdk_pixbuf_render_pixmap_and_mask(ui->bg_pixbuf, NULL, &shape, 255); + + gtk_widget_set_size_request(ui->window, ui->width, ui->height); + gtk_widget_shape_combine_mask(ui->window, shape, 0, 0); + + g_object_unref(shape); + + gtk_widget_realize(ui->window); + + ui->shapes[UI_SHAPE_BUTTON_TINY] = gdk_bitmap_create_from_data(NULL, + (char *) button_tiny_bits, + button_tiny_width, + button_tiny_height); + ui->shapes[UI_SHAPE_BUTTON_SMALL] = gdk_bitmap_create_from_data(NULL, + (char *) button_small_bits, + button_small_width, + button_small_height); + ui->shapes[UI_SHAPE_BUTTON_NORMAL] = gdk_bitmap_create_from_data(NULL, + (char *) button_normal_bits, + button_normal_width, + button_normal_height); + ui->shapes[UI_SHAPE_BUTTON_LARGE] = gdk_bitmap_create_from_data(NULL, + (char *) button_large_bits, + button_large_width, + button_large_height); + ui->shapes[UI_SHAPE_BUTTON_ROUND] = gdk_bitmap_create_from_data(NULL, + (char *) button_round_bits, + button_round_width, + button_round_height); + + + ui->fixed = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(ui->window), ui->fixed); + + ui->background = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(ui->background), + ui->width, ui->height); + x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->background, + 0, 0, ui->width, ui->height); + + x49gp_ui_color_init(&ui->colors[UI_COLOR_BLACK], 0x00, 0x00, 0x00); + x49gp_ui_color_init(&ui->colors[UI_COLOR_WHITE], 0xff, 0xff, 0xff); + x49gp_ui_color_init(&ui->colors[UI_COLOR_YELLOW], 0xfa, 0xe8, 0x2c); + x49gp_ui_color_init(&ui->colors[UI_COLOR_RED], 0x8e, 0x25, 0x18); + x49gp_ui_color_init(&ui->colors[UI_COLOR_GREEN], 0x14, 0x4d, 0x49); + x49gp_ui_color_init(&ui->colors[UI_COLOR_SILVER], 0xe0, 0xe0, 0xe0); + x49gp_ui_color_init(&ui->colors[UI_COLOR_ORANGE], 0xc0, 0x6e, 0x60); + x49gp_ui_color_init(&ui->colors[UI_COLOR_BLUE], 0x40, 0x60, 0xa4); + + + ui->lcd_canvas = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(ui->lcd_canvas), + ui->lcd_width, ui->lcd_height); + x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->lcd_canvas, + ui->lcd_x_offset, ui->lcd_y_offset, + ui->lcd_width, ui->lcd_height); + + + for (i = 0; i < ui->nr_buttons; i++) { + key = &x49gp_ui_keys[i]; + key = &x50g_ui_keys[i]; + button = &ui->buttons[i]; + + button->x49gp = x49gp; + button->key = key; + + button->button = gtk_button_new(); + gtk_widget_set_size_request(button->button, + key->width, key->height); + gtk_widget_set(button->button, "can-focus", FALSE, NULL); + + x49gp_ui_button_pixmaps_init(x49gp, button, key->color); + + if (key->label) { + button->label = gtk_label_new(""); + gtk_widget_set_style(button->label, + button->button->style); + gtk_container_add(GTK_CONTAINER(button->button), + button->label); + + g_signal_connect(G_OBJECT(button->label), + "expose-event", + G_CALLBACK(x49gp_button_expose_event), + button); + + g_signal_connect_after(G_OBJECT(button->label), + "realize", + G_CALLBACK(x49gp_button_realize), + button); + } + + button->box = gtk_event_box_new(); + gtk_event_box_set_visible_window(GTK_EVENT_BOX(button->box), + TRUE); + gtk_event_box_set_above_child(GTK_EVENT_BOX(button->box), + FALSE); + gtk_widget_shape_combine_mask(button->box, + ui->shapes[key->shape], 0, 0); + gtk_container_add(GTK_CONTAINER(button->box), button->button); + + + x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), button->box, + ui->kb_x_offset + key->x, + ui->kb_y_offset + key->y, + key->width, key->height); + + g_signal_connect(G_OBJECT(button->button), + "button-press-event", + G_CALLBACK(x49gp_ui_button_press), button); + + g_signal_connect(G_OBJECT(button->button), + "button-release-event", + G_CALLBACK(x49gp_ui_button_release), button); + + g_signal_connect(G_OBJECT(button->button), + "leave-notify-event", + G_CALLBACK(x49gp_ui_button_leave), button); + + gtk_widget_add_events(button->button, + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_LEAVE_NOTIFY_MASK); + } + + g_signal_connect(G_OBJECT(ui->background), "configure-event", + G_CALLBACK(x49gp_window_configure_event), x49gp); + + g_signal_connect(G_OBJECT(ui->lcd_canvas), "expose-event", + G_CALLBACK(x49gp_lcd_expose_event), x49gp); + g_signal_connect(G_OBJECT(ui->lcd_canvas), "configure-event", + G_CALLBACK(x49gp_lcd_configure_event), x49gp); + + g_signal_connect(G_OBJECT(ui->window), "delete-event", + G_CALLBACK(x49gp_ui_quit), x49gp); + g_signal_connect(G_OBJECT(ui->window), "destroy", + G_CALLBACK(x49gp_ui_quit), x49gp); + + g_signal_connect(G_OBJECT(ui->window), "key-press-event", + G_CALLBACK(x49gp_ui_key_event), x49gp); + g_signal_connect(G_OBJECT(ui->window), "key-release-event", + G_CALLBACK(x49gp_ui_key_event), x49gp); + + g_signal_connect(G_OBJECT(ui->window), "button-press-event", + G_CALLBACK(x49gp_window_button_press), x49gp); + + gtk_widget_add_events(ui->window, + GDK_BUTTON_PRESS_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK); + + gtk_widget_show_all(ui->window); + return 0; +} + +static int +gui_save(x49gp_module_t *module, GKeyFile *keyfile) +{ + return 0; +} + +int +x49gp_ui_init(x49gp_t *x49gp) +{ + x49gp_module_t *module; + + if (x49gp_module_init(x49gp, "gui", gui_init, gui_exit, + gui_reset, gui_load, gui_save, NULL, + &module)) { + return -1; + } + + return x49gp_module_register(module); +} diff --git a/update.scp b/update.scp new file mode 100644 index 0000000..638aa44 --- /dev/null +++ b/update.scp @@ -0,0 +1 @@ +4950_92.bin diff --git a/x49gp.gif b/x49gp.gif new file mode 100644 index 0000000..edb3a35 Binary files /dev/null and b/x49gp.gif differ